如何处理关于核心数据,共享首选项和通知的Mac OS X Helper / Main应用程序体系结构?
对于我正在开发的一个项目(Mac OS X应用程序),我有一些架构上的疑虑。 它基本上由两个元素组成:一个在后台运行的守护进程收集一些数据和一个查看器用来表示收集到的数据。
守护进程应该在状态栏中显示(没有停靠图标),并且包括一个通过状态栏可访问的小菜单。 它将数据保存在核心数据存储中。 其中一个菜单项是打开查看器的链接 。 当这个查看器被打开时,一个正常的 GUI应用程序应该开始包括一个停靠图标和菜单栏。 打开应用程序本身时,也会打开查看器(通过双击图标)。
经过一番尝试,我发现实现这个function的最好方法是创build两个应用程序,代表查看器的主应用程序和代表守护程序的助手实用程序 。 我这样做的原因之一是,不能立即在LSUIElement
值之间切换来强制守护程序/查看器状态。
现在我对这个架构有一些疑问:
-
守护进程和查看器应用程序都使用相同的核心数据存储来保存和检索数据。 当有一个multithreading的应用程序,我知道需要多个
NSManagedObjectContext
对象来正确同步数据。 如何让多个应用程序同时使用相同的核心数据存储? 这甚至可能没有冲突,锁等风险? 我如何保证一致性? -
守护进程应该始终在查看器启动时启动。 我通过循环遍历所有打开的进程并检查守护进程的包标识符是否已列出来实现了这一点。 如果没有,守护进程将使用
NSWorkspace
的launchApplication
启动。 这工作正常。 现在,当用户退出守护进程时,观察者也应该停止。 观察者被告知守护进程停止的最佳方式是什么? 如果守护进程不在,我可以定期检查活动进程并退出查看器,但这听起来有点奇怪。 我宁愿select某种在观众即将closures时发送的通知。 但是,由于这个通知应该在应用程序之间发送和捕获,我不知道哪个简单的通知服务可用。 有什么想法吗? -
该应用程序是沙盒,因为它将分布在Mac App Store上。 使用
NSWorkspace
的launchApplication
启动应用程序会导致目标应用程序在相同的沙盒环境中运行,因为在同一个沙箱中运行这两个应用程序感觉更好 ,可能也是这样。 但想象一下这种情况:守护进程在login时自动启动(使用SMLoginItemSetEnabled
),用户双击Viewer.app。 当守护进程已经运行(再次,这是通过循环活动进程检查),它不会被启动。 现在我们有守护进程和观察者在不同的沙箱中运行了吗? 这是否会导致喜好,核心数据存储等问题? -
我想使用
NSUserDefaults
进行基本configuration,我可以以某种方式在守护进程和查看器之间交换这些数据吗? 同样,这两个应用程序将有不同的包标识符。
在此先感谢您的帮助,感激!
对这个问题没有一个正确的答案,但是我要如何处理这个问题:
守护进程和查看器应用程序都使用相同的核心数据存储来保存和检索数据。
因为在进程之间共享一个Core Data存储是不被支持的(据我所知),我会让守护进程公开一个XPC服务 。 查看者不用打开核心数据存储本身,而是使用NSXPCConnection
通过守护进程访问数据。
假设查看器从不运行没有守护进程,它可以使用SMLoginItemSetEnabled
(就像你在问题中提到的那样)为守护进程注册一个mach服务,然后连接到那个服务。
有一些示例代码覆盖了苹果网站上的设置细节(总结:守护进程需要位于App.app/Contents/Library/LoginItems/daemon.bundle.id.app
),您可能还想阅读这篇博客文章 ,讨论一些由沙盒施加的额外要求(摘要:确保您的团队ID在守护程序的包标识符中)。
守护进程应该始终在查看器启动时启动。
所有设置:一旦您使用SMLoginItemSetEnabled
注册守护进程,launchd将在查看器连接到其XPC服务时启动它(如果需要)。
现在,当用户退出守护进程时,观察者也应该停止。
查看器可以使用NSXPCConnection
来查明守护进程何时退出。 守护进程还可以使用SMLoginItemSetEnabled
在退出前取消注册,以免重新启动。
我想使用
NSUserDefaults
进行基本configuration,我可以以某种方式在守护进程和查看器之间交换这些数据吗? 同样,这两个应用程序将有不同的包标识符。
为此使用一个套件:
// To read or write: NSUserDefaults* suiteDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.example.app.shared"]; [suiteDefaults setObject:[NSDate date] forKey:@"launchTime"]; // Add the suite to -standardUserDefaults to make reading easier: NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults addSuiteNamed:@"com.example.app.shared"];
要使用沙箱,查看器和守护程序必须共享一个应用程序组。 您甚至可以使用KVO来观察对共享密钥的更改。