在Mac OS X上停止后台进程的正确方法是什么?

时间:2010-04-27 18:54:57

标签: objective-c daemon user-agent

我有一个包含2个组件的应用程序:用户与之交互的桌面应用程序,以及可以从桌面应用程序启用的后台进程。启用后台进程后,它将作为独立于桌面应用程序的用户启动代理运行。

然而,我想知道当用户禁用后台进程时该怎么办。此时我想停止后台进程,但我不确定最佳方法是什么。我看到的3个选项是:

  1. 使用'kill'命令。
    • 直接,但不可靠,似乎有些“错误”。
  2. 使用NSMachPort将桌面应用程序的退出请求发送到后台进程。
    • 这是我想过的最好的方法,但我遇到了一个实现问题(我将在一个单独的查询中发布)并且我想确保方法是正确的在走得更远之前。
  3. 别的什么???
  4. 提前感谢您提供的任何帮助/见解。

2 个答案:

答案 0 :(得分:0)

守护程序可以处理退出苹果事件或侦听CFMessagePort。

如果您使用信号,您应该处理发送的信号,可能是SIG_QUIT,而不是让系统终止您的进程。

如果您可能需要一段时间进行清理,请使用除信号之外的其他内容。如果您基本上只是呼叫退出,那么信号就可以了。

如果您已经有CFRunLoop,那么请使用CFMessagePort。如果您已处理苹果事件而不是处理退出。

CFMessagePort是CFMachPort的包装器,提供名称和其他一些便利。你也可以使用NS包装器。

答案 1 :(得分:0)

我发现使用NSConnection对象更简单的方法。我用这个标题创建了一个非常简单的ExitListener对象:

@interface ExitListener : NSObject {
    BOOL _exitRequested;
    NSConnection *_connection;
}

@property (nonatomic, assign) BOOL exitRequested;

- (void)requestExit;

@end

和这个实现:

@implementation ExitListener

@synthesize exitRequested = _exitRequested;

// On init we set ourselves up to listen for an exit
- (id)init {
    if ((self = [super init]) != nil) {
        _connection = [[NSConnection alloc] init];

        [_connection setRootObject:self];
        [_connection registerName:@"com.blahblah.exitport"];
    }
    return self;
}

- (void)dealloc {
    [_connection release];

    [super dealloc];
}

- (void)requestExit {
    [self setExitRequested:YES];
}

@end

要设置监听器,后台进程只需分配并启动ExitListener的实例。桌面应用程序然后通过进行此调用要求后台进程退出:

- (void)stopBackgroundProcess {
    // Get a connection to the background process and ask it to exit
    NSConnection *connection = [NSConnection connectionWithRegisteredName:@"com.blahblah.exitport" host:nil];
    NSProxy *proxy = [connection rootProxy];
    if ([proxy respondsToSelector:@selector(requestExit)]) {
        [proxy performSelector:@selector(requestExit)];
    }
}

直接使用NSMachPorts似乎在注册和获取引用时会导致更多问题。我发现NSConnection是为我需要解决的那种情况创建基本通信通道的最简单方法。