Ответ 1
Таймер - это быстрый мост NSTimer, который восходит к NeXTSTEP, задолго до появления Grand Central Dispatch (GCD) и таких вещей, как DispatchSourceTimer, который появился только до 10.6 (в форме dispatch_source_set_timer) и dispatchAfter (в форме отправки_после).
NSTimer основан на цикле выполнения, который был основным способом параллелизма до GCD. Это совместная параллельная система, предназначенная для работы в одном потоке на одном ядре (хотя она может быть расширена до многопоточных сред).
Хотя цикл выполнения все еще очень важен в Cocoa, он больше не является основным или даже предпочтительным способом управления параллелизмом. Начиная с 10.6, GCD становится все более предпочтительным подходом (хотя добавление API NSTimer на основе блоков в период 10.12 было желанной модернизацией).
На 15-секундной шкале различия в эффективности не имеют значения. Тем не менее, я не понимаю ваш комментарий "Таймер удерживает процессор от перехода в состояние ожидания". Я не верю, что это правда. Процессор определенно все еще перейдет в состояние ожидания при ожидании срабатывания NSTimer.
Я бы не стал запускать цикл запуска только для запуска NSTimer. Вам было бы намного лучше запланировать это в главном цикле выполнения, а затем использовать DispatchQueue.async
для выполнения реальной работы в какой-либо другой очереди.
Как правило, я использую инструмент самого высокого уровня, который отвечает потребностям. Это те, которые Apple, вероятно, оптимизирует лучше всего со временем, когда я внесу наименьшее количество изменений. Например, даты пожара NSTimer автоматически корректируются для повышения энергоэффективности. С DispatchSourceTimer вы получаете контроль над настройкой leeway
чтобы получить то же преимущество, но вы можете установить его (значение по умолчанию равно нулю, что оказывает наименьшее влияние на энергию). Конечно, верно и обратное. DispatchSourceTimer является самым низким уровнем и дает вам максимальный контроль, поэтому, если это то, что вам нужно, то тот, который нужно использовать.
Для вашего примера я лично, вероятно, использовал бы Таймер и просто отправлял бы в частную очередь как часть блока. Но DispatchSourceTimer будет полностью уместным.
asyncAfter - это действительно другая вещь, так как это всегда один выстрел. Это замечательно, если вы хотите один выстрел, но он меняет вещи, если вы хотите повторить. Если вы просто вызываете asyncAfter в блоке для повторения, это будет через 15 секунд после того, как вы в последний раз закончили, вместо того, чтобы быть разнесенными на 15 секунд. Первый будет иметь тенденцию дрейфовать немного позже со временем. Вопрос в следующем: если по какой-то причине ваша задача заняла 5 секунд, хотите ли вы, чтобы следующее событие пожара произошло через 15 секунд после его окончания, или вы хотите, чтобы между каждым событием пожара оставались постоянные 15 секунд? Ваш выбор там будет определять, какой инструмент является правильным.
В качестве небольшого примечания, события NSTimer всегда немного позже, чем они запланированы. Мероприятия GCD с задержкой могут быть немного раньше или немного позже. С практической точки зрения, не существует такой вещи, как "вовремя" (период нулевой длины; вы не попадете в него). Таким образом, вопрос всегда в том, обещали ли вы опоздать, как NSTimer, или вы можете быть рано, как GCD с свободой действий.