NSDefaultRunLoopMode проти NSRunLoopCommonModes


114

Всякий раз , коли я намагаюся завантажити великий файл з фоновим UIScrollView, MPMapViewабо що - то, процес завантаження отримує зупинився , як тільки сенсорний екран iPhone. На щастя, дивовижна публікація блогу від Джорна пропонує альтернативний варіант, який використовується NSRunLoopCommonModesдля з'єднання.

Це змушує мене розглянути деталі двох режимів, NSDefaultRunLoopMode та NSRunLoopCommonModes, але яблучний документ не люб'язно пояснює, крім слова

NSDefaultRunLoopMode

Режим роботи з джерелами введення, крім об'єктів NSConnection. Це найпоширеніший режим запуску циклу.

NSRunLoopCommonModes

Об'єкти, додані до циклу запуску, використовуючи це значення в режимі, відстежуються всіма режимами циклу запуску, які були оголошені членами набору "загальних" режимів; детальніше див. Опис CFRunLoopAddCommonMode.

CFRunLoopAddCommonMode

Джерела, таймери та спостерігачі реєструються в одному або декількох режимах циклу запуску і працюють лише тоді, коли цикл запуску працює в одному з цих режимів. Загальні режими - це набір режимів циклу запуску, для яких можна визначити набір джерел, таймерів та спостерігачів, якими поділяються ці режими. Замість того, щоб зареєструвати джерело, наприклад, для кожного конкретного режиму циклу запуску, ви можете зареєструвати його один раз у загальному псевдорежимі циклу запуску і він буде автоматично зареєстрований у кожному режимі циклу запуску у загальному наборі режимів. Так само, коли режим додається до набору загальних режимів, до нещодавно доданого загального режиму додаються будь-які джерела, таймери або спостерігачі, вже зареєстровані в загальному псевдорежимі.

Може хто-небудь, будь ласка, пояснить їх двома людською мовою?

Відповіді:


204

Цикл запуску - це механізм, який дозволяє системі прокидати сплячі потоки, щоб вони могли управляти асинхронними подіями. Зазвичай, коли ви запускаєте потік (за винятком основної нитки), є можливість запускати потік у циклі запуску чи ні. Якщо потік виконує якусь або тривалу операцію без взаємодії із зовнішніми подіями та без таймерів, вам не потрібен цикл запуску, але якщо ваш потік повинен реагувати на вхідні події, він повинен бути приєднаний до циклу запуску для того, щоб прокидайте нитку, коли приходять нові події. Це стосується NSURLConnectionгенерованих потоків, оскільки вони прокидаються лише над вхідними подіями (з мережі).

Кожен потік може бути пов'язаний з декількома циклами запуску, або може бути пов'язаний з певним циклом запуску, який може бути встановлений для роботи в різних режимах. "Режим циклу запуску" - це умова, що використовується ОС для встановлення деяких правил щодо доставки певних подій або збору їх для доставки пізніше.

Зазвичай всі цикли запуску встановлюються в "режим за замовчуванням", який встановлює спосіб за замовчуванням керувати подіями введення. Наприклад: як тільки відбудеться подія перетягування миші (Mac OS) або дотику (на iOS), режим для цього циклу запуску встановлюється для відстеження подій; це означає, що потік не буде пробуджено в нових мережних подіях, але ці події будуть доставлені пізніше, коли подія введення користувача закінчується і цикл запуску знову встановиться в режим за замовчуванням; Очевидно, це вибір, зроблений архітекторами ОС, щоб надавати пріоритет подіям користувача, а не фоновим подіям.

Якщо ви вирішили змінити режим циклу виконання для NSURLConnectionпотоку, з допомогою scheduleInRunLoop:forModes:, то ви можете призначити нитку спеціального циклу виконання режиму , а не цикл конкретного запуску по замовчуванням. Спеціальний псевдорежим, який називається NSRunLoopCommonModes, використовується багатьма джерелами введення, включаючи відстеження подій. Наприклад, присвоєння NSURLConnectionекземпляра загальному режиму означає, що асоціює його події в "режим відстеження" на додаток до "режиму за замовчуванням". Однією перевагою / недоліком асоціації потоків NSRunLoopCommonModesє те, що потік не буде блокований подіями дотику.

До звичайних режимів можна додати нові режими, але це досить низький рівень роботи.

Я хотів би закрити, додавши кілька приміток:

  • Зазвичай нам потрібно використовувати набір зображень або ескізів, завантажених з мережі, із поданням таблиці. Ми можемо подумати, що завантаження цих зображень з мережі під час прокрутки табличного перегляду може покращити роботу користувачів (оскільки ми могли бачити зображення під час прокрутки), але це не вигідно, оскільки плинність прокрутки може сильно постраждати. У цьому прикладі з NSURLConnectionциклом запуску не слід використовувати; було б краще використовувати UIScrollViewделегатні методи для виявлення припинення прокрутки, а потім оновити таблицю та завантажити нові елементи з мережі;

  • Ви можете скористатися GCD, що допоможе вам захистити свій код від проблем управління циклом. У наведеному вище прикладі ви можете розглянути можливість додавання мережевих запитів до спеціальної послідовної черги.


9
Шановний Viggio24, дуже дякую за це чисте, точне пояснення. Я б попросив Apple включити ваш коментар до їх посібника по API. ;)
Stkim1

7
Відповідь viggio24 ідеальна. Для тих, хто цікавиться, я зазначу, що сесія 208 (Мережеві програми для iPhone OS, частина 2) від WWDC 2010 містить вступ на циклі запуску. Якщо вам цікаво, подивіться. Сподіваюся, це допомагає.
Лоренцо Б

19
Лише зауваження для себе: NSRunLoopCommonModesдозволяє подія таймера під час прокрутки UIScrollView. NSDefaultRunLoopModeзапобігти таймеру під час прокрутки.
eonil

2
Мені цікавим був коментар щодо оновлення подання прокрутки, оскільки він згадує дуже складну тему. Просто для того, щоб додати більше деталей щодо цього: Коли ви встановлюєте режим для NSURLConnection, це впливає лише на виконання делегатних зворотних дзвінків. Я розумію, що оновлення scrollView тут може призвести до проблеми продуктивності, але чому це відбувається? Якщо відповідь полягає в тому, що картинку потрібно завантажити в пам'ять, ви можете це зробити, записавши у графічний контекст на задньому плані та оновивши основний шар перегляду, виконавши це. це звучить розумно?
nebillo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.