Делегировать обратный вызов из другого NSThread - PullRequest
2 голосов
/ 09 августа 2011

У меня есть объект со свойством .delegate, которым я манипулирую в методе doJob.Я назначаю это свойство с помощью «self», и моя функция вызывается, когда этот объект завершает свою работу.До сих пор все в порядке.

Теперь я хочу манипулировать этим объектом в отдельном потоке.

Я использую [NSThread detachNewThreadSelector ...] для запуска функции doJob.В этом случае мой метод делегата не вызывается.Я думаю, это потому, что «я» указывает на новый поток вместо основного.Хорошо.Я передаю себя в качестве аргумента функции при создании потока, и он все еще не работает.Что мне не хватает?

мой текущий код выглядит следующим образом:

- (void)mainFunction
{
    [NSThread detachNewThreadSelector:@selector(doJob:) toTarget:self witObject:self];
}

- (void)doJob:(MyObject*)parentThread
{
    ManipulatedObject *obj = [[ManipulatedObject alloc] init];
    obj.delegate = parentThread;
    [object startJob];
}

Ответы [ 2 ]

1 голос
/ 10 августа 2011

GCD сделает большинство ваших проблем с многопоточностью тривиальными.Вы можете сделать что-то вроде этого:

- (void)mainFunction
{
    // Runs your task on a background thread with default priority.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        ManipulatedObject * obj = [[ManipulatedObject alloc] init];

        [obj startJob];  // I'm assuming this is sychronous.

        // The callback is explicitly run on the main thread.
        dispatch_async(dispatch_get_main_queue(), ^{

            // Your callback here.

            [obj release];
        });
    });
}

Это все, что вам нужно сделать, это так просто.Весь соответствующий код встроен и вместе.

Если вы хотите, чтобы ManipulatedObject явно вызывал блок, вы можете добавить эту способность к ManipulatedObject.Для этого вам следует:

  1. Определить тип блока для удобства typedef void(^MyCallback)();

  2. Добавить @property (nonatomic, copy) MyCallback block; и @synthesize block.Не забудьте копию.

  3. Вызовите блок, когда вам нужно dispatch_async(dispatch_get_main_queue(), [self block]);.

Если ваш делегат должен сделать больше, чемодин вид обратного вызова, тогда вам понадобится блок для каждого обратного вызова.Это небольшое неудобство, но оно того стоит для всех удобств, которые вы получаете.

Для более подробного объяснения блоков и GCD, посетите сеанс WWDC 2011 308.

0 голосов
/ 09 августа 2011

Ну, во-первых, вам не нужно передавать self как параметр witObject: (который пишется неправильно), потому что - (void) doJob: (MyObject *) parentThread все еще находится в одном объекте (self одинаково в обоих потоках), self не имеет ничего общего с вашим основным потоком, предположительно MyObject, у вас также есть проблема, если вы не создаете новый пул автоматического выпуска для doJob :, doJob: должен выглядеть так:

- (void)doJob:(MyObject*)parentThread
{
    NSAutoreleasePool    * pool = [[NSAutoreleasePool alloc] init];
    ManipulatedObject *obj = [[ManipulatedObject alloc] init];
    obj.delegate = parentThread;
    [object startJob];
    [pool release];
}

у вас естьчтобы дать нам некоторую информацию о том, как вызывается ваш делегированный метод, если он использует таймеры или что-то в этом роде, у вас будут проблемы, потому что нет цикла запуска, к которому вы добавляете свой таймер.

...