如何处理有关核心数据,共享偏好和通知的Mac OS X Helper/Main应用程序架构?

Nie*_*aan 48 macos notifications daemon core-data helpers

我对一个正在研究的项目(Mac OS X应用程序)有一些架构上的怀疑.它基本上由两个元素组成:一个在后台运行的守护进程收集一些数据,一个查看器用于表示收集的数据.

守护程序应在状态栏中显示(无停靠图标),并包含可通过状态栏访问的小菜单.它将数据保存在核心数据存储中.其中一个菜单项是打开查看器链接.打开此查看器时,正常的 GUI应用程序应该开始包括停靠图标和菜单栏.打开应用程序本身时也会打开查看器(通过双击图标).

经过一些实验,我发现实现这个功能的最好方法是创建两个应用程序,代表查看器的主应用程序和代表守护进程的辅助工具.我这样做的原因之一是不能LSUIElement立即在值之间切换以强制守护进程/查看器状态.

现在我对这个架构有一些疑问:

  • 守护程序和查看器应用程序都使用相同的核心数据存储来保存和检索数据.拥有多线程应用程序时,我知道NSManagedObjectContext需要多个对象才能正确同步数据.如何让多个应用程序同时使用相同的核心数据存储?这是否可能没有冲突,锁定等风险?我如何保证一致性?

  • 守护程序应始终在查看器启动时启动.我通过简单地遍历所有打开的进程并检查是否列出了守护进程的bundle标识符来实现这一点.如果没有,守护进程使用NSWorkspace's' 开始launchApplication.这很好用.现在,当用户退出守护程序时,查看器也应该停止.查看器通知守护程序停止的最佳方法是什么?如果守护程序消失,我可以定期检查活动进程并退出查看器但听起来有点奇怪.我希望选择某种通知,当观众即将关闭时,我会发送这些通知.但由于应在应用程序之间发送和捕获此通知,因此我不知道哪种简单通知服务可用.有什么想法吗?

  • 该应用程序是沙盒,因为它将在Mac App Store上分发.使用NSWorkspace's 启动应用程序launchApplication会导致目标应用程序在与我认为根本不是问题的源相同的沙盒环境中运行,因为在同一个沙箱中运行这两个应用程序感觉更好,可能是.但想象一下这个场景:守护进程在登录时自动启动(使用SMLoginItemSetEnabled),用户双击Viewer.app.由于守护程序已在运行(再次通过循环执行活动进程来检查),它将无法启动.现在我们有守护进程和查看器在不同的沙箱中运行吗?这会导致偏好,核心数据存储等问题吗?

  • 我想NSUserDefaults用于基本配置,我可以以某种方式在守护进程和查看器之间交换这些数据吗?同样,两个应用程序将具有不同的包标识符.

在此先感谢您的帮助,谢谢!

s4y*_*s4y 2

这个问题没有一个正确的答案,但我的解决方法如下:

守护程序和查看器应用程序都使用相同的核心数据存储来保存和检索数据。

因为不支持在进程之间共享核心数据存储(据我所知),所以我让守护进程公开XPC Service。查看器无需打开核心数据存储本身,而是NSXPCConnection通过守护程序访问数据。

假设查看器在没有守护进程的情况下永远不会运行,它可以使用SMLoginItemSetEnabled,就像您在问题中提到的那样,为守护进程注册一个 mach 服务,然后连接到该服务。

Apple 网站上有示例代码介绍了设置的详细信息(摘要:守护进程需要位于App.app/Contents/Library/LoginItems/daemon.bundle.id.app),您可能还想阅读这篇博客文章,其中讨论了沙箱施加的一些额外要求(摘要:使额外的确保您的团队 ID 在守护程序的包标识符中)。

守护进程应始终在查看器启动时启动。

一切就绪:一旦您使用 注册了守护进程SMLoginItemSetEnabled,当查看器连接到其 XPC 服务时,launchd 将启动它(如果需要)。

现在,当用户退出守护进程时,查看器也应该停止。

查看者可以使用NSXPCConnection来了解守护进程何时退出。守护进程还可以SMLoginItemSetEnabled在退出之前取消注册自身,这样就不会重新启动。

我想用于NSUserDefaults基本配置,我可以以某种方式在守护程序和查看器之间交换此数据吗?同样,两个应用程序将具有不同的包标识符。

为此使用套件:

// 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"];
Run Code Online (Sandbox Code Playgroud)

要使用沙箱,查看器和守护程序必须共享一个应用程序组。您甚至可以使用 KVO 来观察共享密钥的更改。