Подтвердить что ты не робот

Разница в планировании NSTimer в основном потоке и фоновом потоке?

Когда я вызываю scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: в главном потоке и устанавливаю интервал времени scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: 5 секундам, выполняется код ниже таймера, а через 5 секунд вызывается селектор таймера.

Но если я попытаюсь сделать то же самое в некотором фоновом потоке, код ниже scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: не будет выполнено, оно будет ждать срабатывания таймера, а затем будет выполнено. Конечно, чтобы запустить таймер в фоновом потоке, я сначала получил экземпляр NSRunLoop и запустил его.

Есть ли способ установить таймер в фоновом потоке и сделать его неблокирующим, чтобы код сразу же выполнялся?

4b9b3361

Ответ 1

NSTimers запланированы в текущем цикле выполнения потока. Однако потоки отправки GCD не имеют циклов запуска, поэтому таймеры планирования в блоке GCD ничего не сделают.

Там три разумных альтернативы:

  • Выясните, какой цикл цикла вы планируете включить таймер, и явно это сделаете. использование + [NSTimer timerWithTimeInterval: target: selector: userInfo: repeat:], чтобы создать таймер, а затем -[NSRunLoop addTimer:forMode:], чтобы на самом деле запланировать его в цикле выполнения, который вы хотите использовать. Для этого требуется наличие дескриптора в цикле выполнения, но вы можете просто использовать +[NSRunLoop mainRunLoop], если хотите сделать это в основном потоке.

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

  • Явно dispatch_async() вернитесь в основную очередь перед созданием таймера. Это эквивалентно опции №1 с использованием цикла основного запуска (поскольку он также создает таймер в основном потоке).

Конечно, реальный вопрос здесь в том, почему вы создаете таймер из фона?

Ответ 2

NSTimer требует активного цикла выполнения, при инициализации в основном потоке он автоматически использует основной цикл выполнения. Если вам нужно сделать фоновый таймер, вам нужно присоединить его к циклу выполнения потоков и вызвать run(), чтобы сделать его активным.

  1. NSTimer нужен один живой NSRunLoop для выполнения его событий. В основном потоке NSRunLoop всегда активен и никогда не остановится, пока приложение не будет завершено, но в других потоках вы должны вызывать run(), чтобы активировать NSRunLoop.

  2. NSTimer должен вызвать invalidate(), чтобы освободить текущий таймер, в противном случае таймер сохранит сильную ссылку на текущий экземпляр цели и останется в памяти, пока не будет вызван invalidate() или приложение не будет закрыто;

  3. NSTimer должен быть создан и признан недействительным в одном и том же потоке, и часто мы можем об этом забыть.

Взгляните на этот пример, он может быть полезен >> http://www.acttos.org/2016/08/NSTimer-and-GCD-Timer-in-iOS/ и документация: https://developer.apple.com/документация/основа /NSTimer