Как работать с архитектурой Mac OS X Helper/Main, касающейся основных данных, общих предпочтений и уведомлений?

У меня возникли некоторые архитектурные сомнения относительно проекта (приложение Mac OS X), над которым я работаю. Он в основном состоит из двух элементов: демона, который запускается в фоновом режиме, собирает некоторые данные и средство просмотра, используемое для представления собранных данных.

Демон должен быть видимым в строке состояния (без значка док-станции) и включает в себя небольшое меню, доступное через строку состояния. Он сохраняет данные в основном хранилище данных. Одним из пунктов меню является ссылка, которая открывает просмотрщик. Когда этот просмотрщик открыт, приложение обычный GUI должно начинаться с значка док-станции и меню. Средство просмотра также открывается при открытии самого приложения (двойным щелчком по значку).

После некоторых экспериментов я понял, что лучший способ достичь этой функциональности - создать два приложения, основное приложение, представляющее просмотрщик, и вспомогательную утилиту, представляющую демон , Одной из причин, по которой я сделал это, является то, что невозможно мгновенно переключаться между значениями LSUIElement, чтобы заставить состояние демона/зрителя.

Теперь у меня есть некоторые вопросы об этой архитектуре:

  • Оба приложения-демона и зрителя используют одно и то же хранилище данных ядра для сохранения и извлечения данных. При использовании многопоточного приложения я знаю, что для правильной синхронизации данных необходимы несколько объектов NSManagedObjectContext. Как насчет одновременного использования нескольких приложений с одним и тем же хранилищем данных ядра? Возможно ли это даже без риска конфликтов, блокировок и т.д.? Как я могу гарантировать согласованность?

  • Демон должен всегда запускаться при запуске программы просмотра. Я достиг этого, просто перейдя через все открытые процессы и проверяя, указан ли идентификатор пучка демона. Если нет, демон запускается с помощью NSWorkspace launchApplication. Это прекрасно работает. Теперь, когда пользователь выходит из демона, зритель также должен остановиться. Каков наилучший способ уведомления зрителя о прекращении демона? Я могу периодически проверять активные процессы и выходить из программы просмотра, если демон демонтирован, но это звучит немного странно. Я предпочел бы выбрать какое-то уведомление, которое я отправлю, когда зритель собирается закрыть. Но поскольку это уведомление должно быть отправлено и захвачено между приложениями, я не знаю, какая услуга уведомления простая доступна. Любые мысли?

  • Приложение изолировано, поскольку оно будет распространено в Mac App Store. Запуск приложений с NSWorkspace launchApplication заставляет целевое приложение запускаться в той же изолированной среде, что и исходный код, который, как мне кажется, не является проблемой, потому что запуск обоих приложений в одной песочнице выглядит лучше и вероятно, есть. Но представьте себе этот сценарий: демон запускается автоматически при входе в систему (используя SMLoginItemSetEnabled), и пользователь дважды щелкает Viewer.app. Поскольку демон уже запущен (опять же, это проверяется путем циклического перехода через активные процессы), он не будет запущен. Теперь у нас есть демон и зритель, работающий в разных песочницах? Это вызовет проблемы с настройками, хранилищем основных данных и т.д.?

  • Я хотел бы использовать NSUserDefaults для базовой конфигурации, могу ли я каким-то образом обменять эти данные между демоном и зрителем? Опять же, оба приложения будут иметь разные идентификаторы пакетов.

Заранее благодарим за вашу помощь, оценили!

Ответ 1

Нет ответа на эту проблему, но вот как я к этому подхожу:

Оба приложения daemon и viewer используют одно и то же хранилище данных ядра для сохранения и извлечения данных.

Поскольку совместное использование хранилища основных данных между процессами не поддерживается (насколько я знаю), у меня был бы демон демонстрацией XPC Service. Вместо открытия самого хранилища основных данных зритель будет использовать NSXPCConnection для доступа к данным через демона.

Предполагая, что просмотрщик никогда не запускается без демона, он может использовать SMLoginItemSetEnabled, как вы упомянули в вопросе, для регистрации службы mach для демона, а затем подключиться к этой службе.

Вот пример кода, в котором подробно описаны настройки здесь на веб-сайте Apple (резюме: демон должен быть в App.app/Contents/Library/LoginItems/daemon.bundle.id.app), и вы также можете прочитать это сообщение в блоге, в котором обсуждаются некоторые дополнительные требования, предъявляемые песочницей (сводка: убедитесь, что ваша команда ID находится в идентификаторе пакета демона).

Демон должен всегда запускаться при запуске программы просмотра.

Весь набор: после регистрации демона с помощью SMLoginItemSetEnabled запускает его (при необходимости), когда зритель подключается к своей службе XPC.

Теперь, когда пользователь выходит из демона, зритель также должен остановиться.

Зритель может использовать 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 для наблюдения за изменениями общих ключей.