NSDefaultRunLoopMode vs NSRunLoopCommonModes

Дорогие добрые люди stackoverflow,

Как и в прошлый раз, я тем самым поднимаю вопрос, который я недавно наткнулся. Надеюсь, кто-то там может пролить свет на меня.

Всякий раз, когда я пытаюсь загрузить большой файл за UIScrollView, MPMapView или что-то еще, процесс загрузки останавливается, как только я касаюсь экрана iPhone. К счастью, потрясающая запись в блоге Jörn предлагает альтернативный вариант, используя NSRunLoopCommonModes для подключения.

Это заставляет меня заглянуть в детали двух режимов: NSDefaultRunLoopMode и NSRunLoopCommonModes, но документ Apple не любезно объясняет, кроме как сказать

NSDefaultRunLoopMode

Режим работы с источниками входных данных, отличными от объектов NSConnection. Это наиболее часто используемый режим run-loop.

NSRunLoopCommonModes

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

CFRunLoopAddCommonMode

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

Может ли кто-нибудь объяснить это на человеческом языке?

Ответ 1

Цикл запуска - это механизм, который позволяет системе пробуждать спящие потоки, чтобы они могли управлять асинхронными событиями. Обычно, когда вы запускаете поток (за исключением основного потока), есть возможность запустить поток в цикле выполнения или нет. Если поток выполняет некоторую или долгосрочную работу без взаимодействия с внешними событиями и без таймеров, вам не нужен цикл выполнения, но если ваш поток должен отвечать на входящие события, он должен быть привязан к циклу запуска, чтобы пробуждайте поток при поступлении новых событий. Это относится к NSURLConnection сгенерированным потокам, поскольку они только пробуждаются при входящих событиях (из сети).

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

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

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

Новые режимы могут быть добавлены к общим режимам, но это довольно низкоуровневая операция.

Я хотел бы закрыть, добавив несколько заметок:

  • Обычно нам нужно использовать набор изображений или миниатюр, загруженных из сети, с табличным представлением. Мы можем думать, что загрузка этих изображений из сети, в то время как представление таблицы прокрутка может улучшить работу пользователя (поскольку мы могли видеть изображения в то время как прокрутка), но это не выгодно, так как текучесть прокрутка может сильно пострадать. В этом примере с NSURLConnection не следует использовать цикл запуска; было бы лучше использовать методы делегата UIScrollView для обнаружения, когда прокрутка завершается, а затем обновлять таблицу и загружать новые элементы из сети;

  • Вы можете использовать GCD, который поможет вам "защитить" ваш код от проблем управления конвейером. В приведенном выше примере вы можете рассмотрите возможность добавления сетевых запросов в пользовательскую последовательную очередь.