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

时间:2013-10-24 22:02:18

标签: objective-c multithreading macos cocoa 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];
            }
        }
    }
}

2 个答案:

答案 0 :(得分:8)

Apple Developer论坛上的用户实际上建议我观看来自WWDC 2013的视频,题为"使用App Nap提高电源效率&#34 ;;我在其中找到了解决方案:

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);
}

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

答案 1 :(得分:6)

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

如果您使用的是后台应用程序,那么您必须设置“应用程序是代理程序(UIElement)”' (LSUIElement)选项为“是”或“应用程序仅为后台”' (LSBackgroundOnly)在应用程序的plist中选择yes,否则它将受App Nap的限制,这是您在这种情况下遇到的情况。我不希望定时器合并在定时器间隔中产生巨大的间隙。

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

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

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

如果您想阻止用户应用程序遇到App nap,那么您将不得不遵循其中一种支持的机制,导致其中一种状态无效。

如果您使用IOPmlib.h API,则可以为您的应用创建电源管理声明,以防止误打扰。

Alternativaly,您可以使用以下方法禁用自动终止:

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

并再次启用自动终止:

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

但这通常用于需要在考虑应用程序之前完成的代码,并且很好地停止'例如写出偏好。

  

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