Отключение таймера Coalescing в OSX для данного процесса

У меня есть фоновое приложение, которое требует отправить keep-alive в другой процесс каждые 1,5 секунды. Все работает плавно в OSX 10.7 и 10.8, но в OSX 10.9 многие уведомления о сохранении остаются пропущенными, иногда до 3. Обычно все работает нормально в течение первых 3 или 4 минут, после чего возникают проблемы.

После дополнительной проверки кажется, что функция OSX Mavericks "Таймер Coalescing" будет отвечать за принятие решения о продлении запрошенных 1,5 секунд до 4 секунд.

Есть ли способ указать в NSThread не объединиться? Или, по крайней мере, для указания допустимых максимальных изменений коалесценции?

См. приведенный ниже код:

+(void)keepAliveThread
{
    @autoreleasepool {
        void (^keepAlive)() = ^ (){
            // (snipped!) do something...
        };
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        while( [NSThread currentThread].isCancelled == NO )
        {
            @autoreleasepool {
                dispatch_async(mainQueue, keepAlive);
                [NSThread sleepForTimeInterval:1.5];
            }
        }
    }
}

Ответ 1

Пользователь на форумах разработчиков Apple фактически рекомендовал посмотреть видео с WWDC 2013 под названием "Повышение энергоэффективности с помощью приложения Nap"; в котором я нашел решение:

static dispatch_source_t _keepAliveTimer;

+(void)enable
{
    _keepAliveTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, dispatch_get_main_queue());
    dispatch_source_set_event_handler(_keepAliveTimer, ^{
        // do something
    });
    dispatch_source_set_timer(_keepAliveTimer, dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), 1.5 * NSEC_PER_SEC, 0.5 * NSEC_PER_SEC);
    dispatch_resume(_keepAliveTimer);
}

Этот фрагмент кода запускает таймер на 1,5 секунды (давайте или принимайте 0,5 секунды), независимо от состояния LSUIElement, и не позволит App Nap выходить за него только для этого таймера.

Ответ 2

Похоже, что вы используете фоновое приложение без установки соответствующего .plist ключа.

Если вы используете фоновое приложение, то вы должны либо установить для параметра "Приложение агент (UIElement)" (LSUIElement) значение "ДА", либо параметр "Только приложение" (LSBackgroundOnly) для "да" приложение plist, в противном случае это будет подпадать под App Nap, и это то, что вы испытываете в этом случае. Я бы не ожидал, что слияние таймеров приведет к огромным разрывам в таймерных интервалах.

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

App Nap предназначен для работы с пользовательскими приложениями. В соответствии с документами есть 4 вещи, которые заставят приложение быть отправлено в приложение-nap:

  • Это не видно - если все окна приложений либо скрыты другими окнами, либо сведены к минимуму в скрытой доке, а приложение не находится на переднем плане
  • Не слышно
  • Он явно не отключил автоматическое завершение
  • Он не принял никаких утверждений управления питанием

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

Если вы используете API IOPmlib.h, вы можете создать утверждение управления питанием для своего приложения, которое предотвратит сон приложения.

Альтернативно, вы можете отключить автоматическое завершение, используя:

[[NSProcessInfo processInfo] disableAutomaticTermination:@"Good Reason"];

И снова включить автоматическое завершение:

[[NSProcessInfo processInfo] enableAutomaticTermination:@"Good Reason"];

Но это, как правило, предназначено для кода, который должен быть выполнен до того, как приложение считается "хорошим для остановки", например. выписывая предпочтения.

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