Из документа Apple
Обсуждения и ваш пользовательский интерфейс
Если ваше приложение имеет графический пользовательский интерфейс, рекомендуется получать события, связанные с пользователем, и инициировать обновления интерфейса из основного потока вашего приложения. Этот подход помогает избежать проблем с синхронизацией, связанных с обработкой пользовательских событий и отрисовкой содержимого окна. Некоторые фреймворки, такие как Cocoa, обычно требуют такого поведения, но даже для тех, которые этого не делают, это поведение сохраняется в основном потоке. имеет то преимущество, что упрощает логику управления пользовательским интерфейсом. Есть несколько заметных исключений, когда выгодно выполнять графические операции из других потоков. Например, QuickTime API включает в себя ряд операций, которые могут выполняться из вторичных потоков, включая открытие файлов фильмов, рендеринг файлов фильмов, сжатие файлов фильмов, а также импорт и экспорт изображений. Точно так же в Carbon и Cocoa вы можете использовать вторичные потоки для создания и обработки изображений и выполнения других вычислений, связанных с изображениями. Использование вторичных потоков для этих операций может значительно повысить производительность. Если вы не уверены в конкретной графической операции, планируйте выполнять ее из основного потока
Кроме того, классы пользовательского интерфейса не являются потокобезопасными в соответствии с руководство по программированию потоков.
Поэтому избегайте обновления пользовательского интерфейса из потока, отличного от основного потока.
Если вы запустите NSOperation
(в очереди), вы можете обновить свой пользовательский интерфейс (например, после загрузки некоторых данных, необходимых для жизненного цикла вашего приложения), выполнив метод в основном потоке, например следующий:
-(void)main {
// e.g the delegate could be the controller that has the view that you want to update
if (delegate) {
NSURL *url = [delegate urlForDownloadOperation:self];
if ( nil == url ) return;
self.downloadedImage = [[NSImage alloc] initWithContentsOfURL:url];
// e.g. rather than invoking processImage directly on the delegate, ensure that the method draw the image on the main thread
[delegate performSelectorOnMainThread:@selector(processImage:)
withObject:self waitUntilDone:YES];
}
}
Или вы можете отправить уведомление компоненту, которому необходимо обновить пользовательский интерфейс, например:
- (void)main {
NSURL *url = [delegate urlForDownloadOperation:self];
if ( nil == url ) return;
self.downloadedImage = [[NSImage alloc] initWithContentsOfURL:url];
// e.g. send a notificatio to inform some components that it is ready to update the UI with some content
[[NSNotificationCenter defaultCenter] postNotificationName:@"importData" object:self];
}
Компонент, которому необходимо обновить пользовательский интерфейс, зарегистрируется для этого уведомления, например
- (void)processImage:(NSNotification*)notification
{
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(processImage:) withObject:notification waitUntilDone:YES];
return;
}
// update the UI here, you are running on the main thread
}
10.07.2012