Вызвать метод модели с блоком, который будет выполняться в главном потоке - PullRequest
8 голосов
/ 09 февраля 2011

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

, т. Е. Пользовательский интерфейс вызывает метод модели с двумя блоками, один для успеха и один для отказа.

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

Надеюсь, я объяснил это нормально, если нет, то в принципе мои методы модели являются асинхронными, немедленно возвращаются и создают новый поток для запуска операции. Как только операция вернется, я вызову блок, который постобработает возвращенные данные, ТО затем мне нужно вызвать блок для сценария успеха, определенного вызываемым внутри пользовательского интерфейса. Однако блоки сценариев успеха и неудач, определенные в пользовательском интерфейсе, должны вызываться в главном потоке, поскольку мне нужно взаимодействовать с элементами пользовательского интерфейса, что должно быть сделано только в основном потоке, как я считаю.

большое спасибо

Ответы [ 4 ]

36 голосов
/ 09 февраля 2011

Что-то вроде этого, вероятно, то, что вы ищете:

- (void) doSomethingWhichTakesAgesWithArg: (id) theArg
                            resultHandler: (void (^)(BOOL, id, NSError *)) handler
{
    // run in the background, on the default priority queue
    dispatch_async( dispatch_get_global_queue(0, 0), ^{
        id someVar = [theArg computeSomething];

        NSError * anError = nil;
        [someVar transmuteSomehowUsing: self error: &anError];

        // call the result handler block on the main queue (i.e. main thread)
        dispatch_async( dispatch_get_main_queue(), ^{
            // running synchronously on the main thread now -- call the handler
            handler( (error == nil), theArg, anError );
        });
    });
}
10 голосов
/ 09 февраля 2011

Если вы используете GCD, вы можете использовать «получить основную очередь»:

dispatch_queue_t dispatch_get_main_queue()

Вызвать это внутри асинхронной отправки.т.е.

dispatch_async(dispatch_get_main_queue(), ^{
  /* Do somthing here with UIKit here */
})

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

6 голосов
/ 07 сентября 2011

Аналогичный подход работает и с NSOperationQueue:

NSBlockOperation *aOperation = [NSBlockOperation blockOperationWithBlock:^ 
 {  
    if ( status == FAILURE )
    { 
        // Show alert -> make sure it runs on the main thread
        [[NSOperationQueue mainQueue] addOperationWithBlock:^ 
         {
             UIAlertView    *alert = [[[UIAlertView alloc] initWithTitle:@"Alert" message:@"Your action failed!" delegate:nil 
                                      cancelButtonTitle:@"Ok" otherButtonTitles:nil] autorelease];
             [alert show];
         }];
    }
 }];

// myAsyncOperationQueue is created somewhere else
[myAsyncOperationQueue addOperation:aOperation];
5 голосов
/ 09 февраля 2011

NSObject имеет метод:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait

Создайте метод, который принимает параметр NSDictionary в удобном классе, который всегда будет рядом (например, делегат приложения или объект-одиночка), упакуйте блоки его параметры в NSDictionary или NSArray и вызовите

[target performSelectorOnMainThread:@selector(doItSelector) withObject:blockAndParameters waitUntilDone:waitOrNot];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...