49

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

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

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

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

  • 守护程序和查看器应用程序都使用相同的核心数据存储来保存和检索数据。当拥有多线程应用程序时,我知道需要多个NSManagedObjectContext对象才能正确同步数据。让多个应用程序同时使用同一个核心数据存储会怎么样?这甚至可以在没有冲突、锁定等风险的情况下实现吗?如何保证一致性?

  • 守护程序应始终在查看器启动时启动。我通过简单地循环所有打开的进程并检查是否列出了守护程序的捆绑标识符来实现这一点。如果不是,则使用NSWorkspace's启动守护程序launchApplication。这工作正常。现在,当用户退出守护程序时,查看器也应该停止。通知查看者守护程序停止的最佳方式是什么?如果守护进程消失,我可以定期检查活动进程并退出查看器,但这听起来有点奇怪。我宁愿选择在查看器即将关闭时发送的某种通知。但是由于这个通知应该在应用程序之间发送和捕获,我不知道哪个简单的通知服务可用。有什么想法吗?

  • 该应用程序被沙盒化,因为它将在 Mac App Store 上分发。NSWorkspace使用's启动应用程序launchApplication会导致目标应用程序在与源应用程序相同的沙盒环境中运行,我认为这根本不是问题,因为在同一个沙盒中运行两个应用程序感觉更好,而且可能确实如此。但是想象一下这种情况:在登录时自动启动守护进程(使用SMLoginItemSetEnabled),并且用户双击 Viewer.app。由于守护进程已经在运行(同样,这是通过循环通过活动进程来检查的)它不会被启动。现在我们让守护进程和查看器在不同的沙箱中运行,对吧?这会导致偏好、核心数据存储等方面的任何问题吗?

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

提前感谢您的帮助,不胜感激!

4

1 回答 1

2

这个问题没有一个正确的答案,但这是我的处理方法:

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

因为不支持在进程之间共享核心数据存储(据我所知),我会让守护进程公开一个XPC Service。查看器不会打开 Core Data 存储本身,而是使用 anNSXPCConnection通过守护进程访问数据。

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

在 Apple 的网站上,有一个示例代码详细介绍了设置的详细信息摘要:守护进程需要位于确保您的团队 ID 在守护程序的包标识符中)。App.app/Contents/Library/LoginItems/daemon.bundle.id.app

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

全部设置:一旦你用 注册了守护进程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"];

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

于 2017-07-30T22:56:10.833 回答