首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >可靠地检测计算机是否会进入休眠状态

可靠地检测计算机是否会进入休眠状态
EN

Stack Overflow用户
提问于 2018-07-10 22:07:50
回答 2查看 1.7K关注 0票数 3

我们正在为mac编写一个Swift应用程序,其中需要检测计算机的睡眠时间戳。

我们已经发现NSWorkspace.willSleepNotificationNSWorkspace.didWakeNotification不够可靠,因为在很少的情况下,只有在PC醒来并能够处理当前堆栈时才会调用NSWorkspace.willSleepNotification。你还有其他建议吗?

EN

回答 2

Stack Overflow用户

发布于 2019-02-28 23:10:06

在10.14.2查看了AppKit的反汇编之后,我发现NSWorkspace.willSleepNotification是在较低级别的IOKit IORegisterForSystemPower API之上实现的。因此,对于大多数用例来说,使用更高级别的AppKit API就足够了.

一个问题是,AppKit将使用CFRunLoopPerformBlockkCFRunLoopCommonModes在主运行循环中对通知的发布进行排队。因此,如果主线程被阻塞,或者主运行循环当前正在运行的模式不是常见的模式之一,那么通知的发布将被延迟。然而,电源管理系统给每个进程30秒的时间来响应通知,因此,一个应用程序极不可能在计算机睡觉前就被屏蔽而错过通知。(如果有可能发生这种情况,那么应用程序应该重新设计,以免阻塞主线程。)

票数 3
EN

Stack Overflow用户

发布于 2018-07-16 17:09:10

您可以向系统电源管理器注册回调(请参阅IORegisterForSystemPower)。当系统想要睡觉时(您可以建议它不睡觉),您的回调函数就会被调用,即将进入休眠状态,并且当它再次醒来时。

这个目标-C包装器是十多年前由菲利普·陶氏( Philip )贡献的,至今仍运转良好。这些年来,我可能做了一些轻微的修改,以便为最新的操作系统和Xcode进行编译,但在其他方面没有变化。(注意:原来的网站已经不存在了,所以我就把它粘贴到这里。)用Swift、到Obj代码的桥、或者仅仅使用它作为使用IORegisterForSystemPower并编写自己的回调函数的示例(如果您想要精确的时间)来重写它是很简单的。

要使用Philip的代码,只需调用+sharedPowerManagement创建单例管理器,然后向通知中心注册观察者以接收PDPowerManagementNotification通知。还有一个委托使用模型。

代码语言:javascript
运行
复制
//
//  PDPowerManagement.h
//  Originally part of the Journler project: http://journler.phildow.net
//  Source code available at http://developers.phildow.net
//
//  Created by Philip Dow on 3/21/06.
//  Licensed under the LGPL: http://www.gnu.org/copyleft/lesser.html
//  You may modify and redistribute the code as needed.
//  Please keep this original notice intact.
//
//  Of course, I would appreciate a mentioning in your app's about box.
//  If you make improvements or additions to the code, please let me know.
//

#import <Cocoa/Cocoa.h>

//
// Be sure to include the IOKit Framework in your project

#import <mach/mach_port.h>
#import <mach/mach_interface.h>
#import <mach/mach_init.h>

#import <IOKit/pwr_mgt/IOPMLib.h>
#import <IOKit/IOMessage.h>

//
// Notifications
//
// The PDPowerManagementNotification will be sent to the default notification center
// with the shared instance of PDPowerManagement as the object. To make sure that a shared
// instance is available, call [PDPowerManagement sharedPowerManagement] somewhere in your code.
//
// The notification's user info dictionary will contain the PDPowerManagementMessage key with an
// NSNumber whose int value is either PDPowerManagementWillSleep or PDPowerManagementPoweredOn.

#define PDPowerManagementNotification   @"PDPowerManagementNotification"
#define PDPowerManagementMessage        @"PDPowerManagementMessage"
#define PDPowerManagementWillSleep      1
#define PDPowerManagementPoweredOn      3

//
// Disallowing Sleep
//
// There are two ways to disallow a power down. Either call setPermitSleep: with NO
// or implement the - (BOOL) shouldAllowIdleSleep:(id)sender delegate method and return NO as needed.
// At initialization _permitSleep is set to YES. With this value, the delegate method is
// always called if the delegate implements it. If _permitSleep is set to NO, the delegate
// method is never called. setPermitSleep: is thus a lazy way of always disallowing sleep.
//
// It must however be noted that it is not possible to cancel a sleep command that the user
// initiates. _permitSleep and the delegate method can only prevent an idle sleep. For
// more information: http://developer.apple.com/qa/qa2004/qa1340.html

@interface PDPowerManagement : NSObject {

    BOOL    _permitSleep;
    id      _delegate;

}

+ (id)sharedPowerManagement;

- (BOOL) permitSleep;
- (void) setPermitSleep:(BOOL)permitSleep;

- (id) delegate;
- (void) setDelegate:(id)delegate;

- (void) _postPMNotification:(NSInteger)message;
- (BOOL) _shouldAllowSleep;

@end

//
// Delegation
// You should implement: - (BOOL) shouldAllowIdleSleep:(id)sender
//
// If you set a delegate, before the computer is put to idle sleep the delegate's
// shouldAllowSleep: method will be called. Return NO to disallow the power down,
// return yes to permit it.

@interface NSObject (PDPowerManagementDelegate)

//
// return YES to permit a power down, NO to disallow it
- (BOOL) shouldAllowIdleSleep:(id)sender;

@end

代码语言:javascript
运行
复制
//
//  PDPowerManagement.m
//  Journler
//
//  Created by Philip Dow on 3/21/06.
//  Copyright 2006 __MyCompanyName__. All rights reserved.
//

#import "PDPowerManagement.h"

@implementation PDPowerManagement

PDPowerManagement   *_self;
io_connect_t        root_port;

static void callback(void * x,io_service_t y,natural_t messageType,void * messageArgument)
{
    switch ( messageType ) {
        case kIOMessageSystemWillSleep:
            if ( [_self _shouldAllowSleep] ) {
                [_self _postPMNotification:PDPowerManagementWillSleep];
                IOAllowPowerChange(root_port,(long)messageArgument);
            }
            else
                IOCancelPowerChange(root_port,(long)messageArgument);
            break;
        case kIOMessageCanSystemSleep:
            IOAllowPowerChange(root_port,(long)messageArgument);
            break;
        case kIOMessageSystemHasPoweredOn:
            [_self _postPMNotification:PDPowerManagementPoweredOn];
            break;
    }

}

#pragma mark -

+ (id)sharedPowerManagement {
    static PDPowerManagement *sharedPowerManagement = nil;

    if (!sharedPowerManagement)
        sharedPowerManagement = [[PDPowerManagement allocWithZone:NULL] init];

    return sharedPowerManagement;
}


- (id)init
{

    if ( (self=[super init])!=nil )
        {
        IONotificationPortRef   notify;
        io_object_t             anIterator;

        root_port = IORegisterForSystemPower (0,&notify,callback,&anIterator);
        if ( root_port == IO_OBJECT_NULL ) {
            NSLog(@"IORegisterForSystemPower failed");
            return nil;
        }

        CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);

        _permitSleep = YES;
        _self = self;

    }

    return self;
}

#pragma mark -

- (BOOL) permitSleep { return _permitSleep; }

- (void) setPermitSleep:(BOOL)permitSleep {
    _permitSleep = permitSleep;
}

- (id) delegate { return _delegate; }

- (void) setDelegate:(id)delegate {
    _delegate = delegate;
}

#pragma mark -

- (void) _postPMNotification:(NSInteger)message {

    NSNumber *dictionaryMessage;
    NSDictionary *userInfo;
    NSNotification *notification;


    // Useful for debugging
    /*
    switch ( message ) {

        case PDPowerManagementWillSleep:
            NSLog(@"Going to sleep now");
            break;
        case PDPowerManagementPoweredOn:
            NSLog(@"Just had a nice snooze");
            break;

    }
    */

    dictionaryMessage = [NSNumber numberWithInteger:message];
    userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
            dictionaryMessage, PDPowerManagementMessage, nil];
    notification = [NSNotification notificationWithName:PDPowerManagementNotification
            object:self userInfo:userInfo];

    [[NSNotificationCenter defaultCenter] postNotification:notification];

}

- (BOOL) _shouldAllowSleep {

    if ( !_permitSleep )
        return NO;
    else {
        if ( _delegate && [_delegate respondsToSelector:@selector(shouldAllowIdleSleep:)] )
            return [_delegate shouldAllowIdleSleep:self];
        else
            return YES;
    }
}

@end
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51276280

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档