Хобрук: Ваш путь к мастерству в программировании

создание элементов пользовательского интерфейса в неосновных очередях NSOperationQueue вызывает странное поведение

У меня был код, который создавал и добавлял UIView подпредставления через очередь, созданную [[NSOperationQueue alloc] init], и это приводило к странным задержкам. Подпредставления добавлялись только после аномально длительных задержек.

Но потом я переключился на использование [NSOperationQueue mainQueue] для этих частей, и отзывчивость стала нормальной.

Я просто хотел бы объяснить запаздывающее поведение, которое я видел, используя первый подход.


Ответы:


1

Из документа 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
Новые материалы

Прогресс в технологии Трансформеров часть 3
Многомасштабный управляющий сигнальный преобразователь для бесфазного синтеза движения (arXiv) Автор: Линтао Ван , Кун Ху , Лей Бай , Юй Дин , Ваньли Оуян , Чжиюн Ван . Аннотация:..

Представляем поддержку компонентов Vue.js. Мгновенный HMR и многое другое.
Хотя у FuseBox уже был плагин Vue, он был базовым и не имел многих функций, которые делали работу с Vue.js такой приятной. Однако с этим выпуском мы рады сообщить, что в FuseBox..

Приключения в Javascript, часть 1
Я продолжаю думать о том, чтобы писать больше, но чем больше я думаю об этом, тем меньше я это делаю. Итак, сегодня я перестал думать и начал писать. Отсюда можно только спускаться… В..

Понимание дженериков в TypeScript: подробное руководство
Введение TypeScript, строго типизированный надмножество JavaScript, хорошо известен своей способностью улучшать масштабируемость, удобочитаемость и ремонтопригодность приложений. Одной из..

Учебные заметки JavaScript Object Oriented Labs
Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

Разбор строк запроса в vue.js
Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
«Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..