Как оптимизировать обратные вызовы из потока, запущенного NSOperationQueue - PullRequest
1 голос
/ 17 января 2010

Учтите это:

@interface SomeViewController : UIViewController {
    SomeChildObject *child;
}
@end

@implementation SomeViewController

- (void) viewDidLoad {
    ...
    child.delegate = self;
}

- (void) somethingHappened {
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]
        initWithTarget:child
        selector:@selector(doSomething)
        object:nil];
[someNsOperationQueue addOperation:operation];
[operation release];
}

- (void) callbackA:(SomeData *)someData {
[self performSelectorOnMainThread:@selector(callbackAonMainThread:)
                       withObject:someData
                    waitUntilDone:NO];
}

- (void) callbackAonMainThread:(SomeData *)someData {
    ... do something with results in main thread, e.g UI feedback
}

- (void) callbackB:(SomeData *)someData {
[self performSelectorOnMainThread:@selector(callbackBonMainThread:)
                       withObject:someData
                    waitUntilDone:NO];
}

- (void) callbackBonMainThread:(SomeData *)someData {
    ... do something with results in main thread, e.g UI feedback
}


@end

На английском языке:

У меня есть контроллер представления, работающий в главном потоке с объектом дочерней модели, чтобы что-то делать (получать данные по сети). Контроллер представления является делегатом для дочернего элемента, поэтому дочерний элемент может передать результаты обратно с делегированием. Чтобы выполнить дорогостоящую работу, я породил метод child.doSomething с NSInvocationOperation, который запускает операцию в фоновом потоке. Когда это сделано, дочерний процесс вызывает callbackA или callbackB делегата (контроллера представления) с некоторыми результатами. Поскольку (я думаю) эти обратные вызовы вызываются в том же фоновом потоке, где был запущен вызов doSomething, мне нужно вызвать executeSelectorOnMainThread для передачи управления обратно в основной поток.

Это прекрасно работает, но мне не нравится иметь два метода, связанных с обратным вызовом, для каждого обратного вызова. (На самом деле существует больше обратных вызовов, поэтому реальный код еще более раздут.) В идеале я бы сделал что-то вроде этого:

- (void) callbackA:(SomeData *)someData {
    if (not_running_on_main_thread) {
    [self performSelectorOnMainThread:@selector(callbackA:)
                       withObject:someData
                    waitUntilDone:NO];
    } else {
        // now running on main thread, work with the results.
    }
}

Вопросы:

1) как мне выполнить тест not_running_on_main_thread?

2) есть ли какой-нибудь другой способ сократить количество обратных вызовов?

РЕДАКТИРОВАТЬ: хорошо, я никогда не читал документы NSThread перед публикацией :) похоже, что [NSThread isMainThread] это то, что я ищу. Но есть ли другой способ реструктурировать или сделать это еще лучше?

1 Ответ

6 голосов
/ 17 января 2010

Просто проверьте на [NSThread isMainThread].Вы ничего не можете сделать, если вам нужно несколько обратных вызовов, которые делают разные вещи.

Только одно я делаю по-другому, мой код выглядит так:

- (void) callbackA:(SomeData *)someData {
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(callbackA:)
                       withObject:someData
                    waitUntilDone:NO];
        return;
    }

    // now running on main thread, work with the results.
}

Это позволяет мне избавитьсяцелую-длинную else и сделать код немного понятнее.И вы можете сэкономить на одном уровне отступа таким образом; -)

...