Разница в планировании NSTimer в основном потоке и фоновом потоке?
Когда я вызываю scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
в главном потоке и устанавливаю интервал времени scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
5 секундам, выполняется код ниже таймера, а через 5 секунд вызывается селектор таймера.
Но если я попытаюсь сделать то же самое в некотором фоновом потоке, код ниже scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
не будет выполнено, оно будет ждать срабатывания таймера, а затем будет выполнено. Конечно, чтобы запустить таймер в фоновом потоке, я сначала получил экземпляр NSRunLoop
и запустил его.
Есть ли способ установить таймер в фоновом потоке и сделать его неблокирующим, чтобы код сразу же выполнялся?
Ответы
Ответ 1
NSTimers запланированы в текущем цикле выполнения потока. Однако потоки отправки GCD не имеют циклов запуска, поэтому таймеры планирования в блоке GCD ничего не сделают.
Там три разумных альтернативы:
-
Выясните, какой цикл цикла вы планируете включить таймер, и явно это сделаете. использование
+ [NSTimer timerWithTimeInterval: target: selector: userInfo: repeat:], чтобы создать таймер, а затем
-[NSRunLoop addTimer:forMode:]
, чтобы на самом деле запланировать его в цикле выполнения, который вы хотите использовать. Для этого требуется наличие дескриптора в цикле выполнения, но вы можете просто использовать +[NSRunLoop mainRunLoop]
, если хотите сделать это в основном потоке.
-
Переключитесь на использование источника отправки по таймеру. Это реализует таймер в механизме, поддерживающем GCD, который будет запускать блок с интервалом, который вы хотите, в выбранной вами очереди.
-
Явно dispatch_async()
вернитесь в основную очередь перед созданием таймера. Это эквивалентно опции №1 с использованием цикла основного запуска (поскольку он также создает таймер в основном потоке).
Конечно, реальный вопрос здесь в том, почему вы создаете таймер из фона?
Ответ 2
NSTimer требует активного цикла выполнения, при инициализации в основном потоке он автоматически использует основной цикл выполнения. Если вам нужно сделать фоновый таймер, вам нужно присоединить его к циклу выполнения потоков и вызвать run(), чтобы сделать его активным.
-
NSTimer нужен один живой NSRunLoop для выполнения его событий. В основном потоке NSRunLoop всегда активен и никогда не остановится, пока приложение не будет завершено, но в других потоках вы должны вызывать run(), чтобы активировать NSRunLoop.
-
NSTimer должен вызвать invalidate(), чтобы освободить текущий таймер, в противном случае таймер сохранит сильную ссылку на текущий экземпляр цели и останется в памяти, пока не будет вызван invalidate() или приложение не будет закрыто;
-
NSTimer должен быть создан и признан недействительным в одном и том же потоке, и часто мы можем об этом забыть.
Взгляните на этот пример, он может быть полезен >> http://www.acttos.org/2016/08/NSTimer-and-GCD-Timer-in-iOS/ и документация: https://developer.apple.com/документация/основа /NSTimer