在OSX中为给定进程禁用定时器合并

eks*_*pto 12 macos cocoa multithreading objective-c osx-mavericks

我有一个后台应用程序,需要每1.5秒向另一个进程发送一个keep-alive.在OSX 10.7和10.8中一切都运行顺畅,但在OSX 10.9下,许多保持活动通知都会丢失,有时会达到3次.通常情况下,前3或4分钟一切正常,然后问题就开始发生了.

经过进一步检查,似乎OSX Mavericks"定时器合并"功能将负责决定将请求的1.5秒延长到4.0秒.

有没有办法在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];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

eks*_*pto 8

Apple开发者论坛上的用户实际上建议我观看来自WWDC 2013的视频"用App 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);
}
Run Code Online (Sandbox Code Playgroud)

无论LSUIElement状态如何,这段代码都将以1.5秒(给出或持续0.5秒)触发计时器,并且将阻止App Nap仅为该计时器启动.


Pet*_*esh 6

听起来你在没有设置适当的.plist密钥的情况下运行后台应用程序.

如果您正在使用后台应用程序,那么您必须在应用程序的plist 中将'Application is agent(UIElement)'(LSUIElement)选项设置为YES或将'Application is background only'(LSBackgroundOnly)选项设置为yes,否则它将成为主题到App Nap,这是你在这种情况下遇到的.我不希望定时器合并在定时器间隔中产生巨大的间隙.

LSUIElement适用于可能只有浮动窗口或状态栏项目的应用程序.他们没有菜单栏,他们没有得到停靠图标.

App Nap旨在影响前期用户应用程序.根据文档,有4件事会导致应用程序被发送到app-nap:

  • 它是不可见的 - 如果所有应用程序的窗口都被其他窗口隐藏或在隐藏的停靠栏中最小化,并且应用程序不在前台
  • 听不见
  • 它没有明确禁用自动终止
  • 它没有采取任何电源管理断言

如果要阻止用户应用程序遇到App nap,则必须遵循其中一种受支持的机制,以使其中一个状态不活动.

如果您使用IOPmlib.h API,您可以为您的应用程序创建电源管理断言,这将阻止应用程序休息.

另外,您可以使用以下命令禁用自动终止:

[[NSProcessInfo processInfo] disableAutomaticTermination:@"Good Reason"];
Run Code Online (Sandbox Code Playgroud)

并再次启用自动终止:

[[NSProcessInfo processInfo] enableAutomaticTermination:@"Good Reason"];
Run Code Online (Sandbox Code Playgroud)

但这通常是针对需要在应用被视为"良好停止"(例如写出偏好)之前完成的代码.

Apple会在文档中的某个位置声明,如果您的应用程序遇到与app nap相关的问题,您应该提交雷达,以便确定它是否是实施中的错误.

  • 您可以使用'taskinfo'命令检查app nap是否正在应用.如果是,您可以使用新的NSProcessInfo API(不是自动终止,10.9中的新),以及调度计时器的新"精确"标志.请注意,sleep()受到应用程序打盹的方式与NSTimer和其他所有类似计时器的方式完全相同. (3认同)