macos - 如何处理有关核心数据、共享首选项和通知的 Mac OS X Helper/Main 应用程序架构?

标签 macos core-data notifications daemon helper

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

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

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

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

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

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

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

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

预先感谢您的帮助,非常感谢!

最佳答案

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

Both the daemon and viewer application uses the same core data store to save and retrieve data.

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

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

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

The daemon should always start when the viewer starts.

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

Now when the user quits the daemon, the viewer should also stop.

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

I would like to use NSUserDefaults for basic configuration, can I somehow interchange this data between the daemon and the viewer? Again, both applications will have different bundle identifiers.

为此使用套件:

// 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 来观察共享 key 的更改。

关于macos - 如何处理有关核心数据、共享首选项和通知的 Mac OS X Helper/Main 应用程序架构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14315048/

相关文章:

xcode - 使用自定义构建 Shell 脚本加密 Cocoa 资源

ios - 如何创建合适的 iOS CoreData 数据库模型?

ios - iOS 8 中 UIKeyboardWillShowNotification 事件的动画 View

php - 队列中的通知不发送电子邮件

macos - 为什么我被迫在 OS X 上使用 sudo 运行 docker?

c++ - 类方法 VS 类静态函数 VS 简单函数 - 性能方面?

c++ - 如何在 macbookpro 上的 makefile 中包含 GLUI 框架?

iphone - 将 CSV 加载到 Core Data 托管的 sqlite 数据库中

ios - 自定义获取核心数据(快速)

java - 更新太多通知导致卡顿,如何改善?