Кто-нибудь может объяснить, что это такое NSRunLoop
? так как я знаю NSRunLoop
, это что-то связано с NSThread
правильным? Итак, предположим, я создаю поток вроде
NSThread* th=[[NSThread alloc] initWithTarget:self selector:@selector(someMethod) object:nil];
[th start];
-(void) someMethod
{
NSLog(@"operation");
}
так что после того, как этот поток закончит свою работу? зачем использовать RunLoops
или где использовать? из документации Apple Я кое-что прочитал, но мне это не ясно, поэтому, пожалуйста, объясните как можно проще
ios
objective-c
cocoa-touch
nsrunloop
тафарель
источник
источник
Ответы:
Цикл выполнения - это абстракция, которая (среди прочего) предоставляет механизм для обработки системных источников ввода (сокеты, порты, файлы, клавиатура, мышь, таймеры и т. Д.).
Каждый NSThread имеет свой собственный цикл выполнения, доступ к которому можно получить с помощью метода currentRunLoop.
В общем, вам не нужно напрямую обращаться к циклу выполнения, хотя есть некоторые (сетевые) компоненты, которые могут позволить вам указать, какой цикл выполнения они будут использовать для обработки ввода-вывода.
Цикл выполнения для данного потока будет ждать, пока один или несколько его источников ввода не получат какие-либо данные или событие, а затем запустят соответствующий обработчик (ы) ввода для обработки каждого источника ввода, который «готов».
После этого он вернется в свой цикл, обрабатывая входные данные из различных источников и «спит», если нет работы.
Это довольно подробное описание (попытка избежать слишком большого количества деталей).
РЕДАКТИРОВАТЬ
Попытка ответить на комментарий. Я разбил его на части.
На самом деле. NSRunLoop не является потокобезопасным, и к нему следует обращаться только из контекста потока, в котором выполняется цикл.
Если вы хотите отслеживать порт, вы просто добавляете этот порт в цикл выполнения, а затем цикл выполнения будет отслеживать активность этого порта.
Вы также можете явно добавить таймер с помощью
Цикл выполнения будет обрабатывать все события готовности на каждой итерации (в соответствии со своим режимом). Вам нужно будет просмотреть документацию, чтобы узнать о режимах запуска, поскольку это немного выходит за рамки общего ответа.
В большинстве приложений основной цикл выполнения запускается автоматически. Однако вы несете ответственность за запуск цикла выполнения и реагирование на входящие события для потоков, которые вы запускаете.
Я не понимаю, что вы здесь имеете в виду. Вы не добавляете события в цикл выполнения. Вы добавляете источники ввода и источники таймера (из потока, которому принадлежит цикл выполнения). Затем цикл выполнения отслеживает их активность. Вы, конечно, можете обеспечить ввод данных из других потоков и процессов, но ввод будет обрабатываться циклом выполнения, который отслеживает эти источники в потоке, в котором выполняется цикл.
На самом деле. Фактически, цикл выполнения будет «оставаться» в обработчике событий до тех пор, пока этот обработчик событий не вернется. Вы можете достаточно просто увидеть это в любом приложении. Установите обработчик для любого действия ввода-вывода (например, нажатия кнопки), которое засыпает. Вы заблокируете основной цикл выполнения (и весь пользовательский интерфейс), пока этот метод не завершится.
То же самое относится к любому циклу выполнения.
Я предлагаю вам прочитать следующую документацию по циклам выполнения:
https://developer.apple.com/documentation/foundation/nsrunloop
и как они используются в потоках:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1
источник
performSelector:onThread:withObject:waitUntilDone:
, передавNSThread
объект, и ваш селектор будет запланирован на цикл выполнения этого потока.Они позволяют вам ждать, пока пользователь коснется и отреагировать соответствующим образом, дождаться, пока вы получите CompletionHandler и применить его результаты, дождаться, пока вы не получите таймер и выполнить функцию. Если у вас нет цикла выполнения, вы не можете слушать / ждать нажатий пользователя, вы не можете ждать, пока произойдет сетевой вызов, вас нельзя разбудить через x минут, если вы не используете
DispatchSourceTimer
илиDispatchWorkItem
Также из этого комментария :
В частности, о: «Фоновые потоки не имеют собственных циклов выполнения». Следующий таймер не срабатывает для асинхронной отправки:
Я думаю, что
sync
блок также запускается потому, что:блоки синхронизации обычно просто выполняются из своей исходной очереди. В этом примере исходная очередь является основной, а любая очередь - целевой.
Чтобы проверить это, я заходил
RunLoop.current
в каждую рассылку.У отправки синхронизации был такой же цикл выполнения, что и у основной очереди. В то время как RunLoop в блоке async отличался от других экземпляров. Вы можете подумать, почему
RunLoop.current
возвращается другое значение. Разве это не общая ценность !? Отличный вопрос! Читайте дальше:ВАЖНАЯ ЗАМЕТКА:
Свойство класса
current
НЕ является глобальной переменной.Это контекстно. Это видно только в рамках потока, то есть в локальном хранилище потока . Подробнее об этом см. Здесь .
Это известная проблема с таймерами. У вас не будет такой же проблемы, если вы используете
DispatchSourceTimer
источник
RunLoops чем-то напоминает ящик, в котором что-то происходит.
По сути, в RunLoop вы обрабатываете некоторые события, а затем возвращаетесь. Или верните, если он не обрабатывает никаких событий до истечения времени ожидания. Вы можете сказать, что это похоже на асинхронные NSURLConnections, Обработка данных в фоновом режиме без вмешательства в ваш текущий цикл, но в то же время вам требуются данные синхронно. Это можно сделать с помощью RunLoop, который делает ваш асинхронным
NSURLConnection
и предоставляет данные во время вызова. Вы можете использовать RunLoop следующим образом:В этом цикле выполнения он будет выполняться до тех пор, пока вы не завершите какую-либо другую работу и не установите для YourBoolFlag значение false .
Точно так же вы можете использовать их в потоках.
Надеюсь, это тебе поможет.
источник
Отсюда
Отсюда
источник