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

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

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

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

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

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

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

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

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

Заранее спасибо за помощь, ценю!


person Niels Mouthaan    schedule 14.01.2013    source источник
comment
Кажется, у меня похожая проблема с созданием инструмента демона/помощника, который будет взаимодействовать с двумя разными приложениями и делиться настройками (только без Mac App Store и песочницы), вы как-то решили это?   -  person Thunder    schedule 23.04.2014
comment
Ваши вопросы интересны, и я хотел бы знать некоторые решения. Может быть, легче получить ответы, когда вы разделяете их?   -  person ctietze    schedule 19.08.2014
comment
Вам еще не повезло? Я хотел бы поговорить о теме. Вы можете найти меня в Твиттере: @ctietze   -  person ctietze    schedule 03.01.2015
comment
В конце концов я решил разработать одно приложение вместо разработки двух отдельных приложений. Однако я считаю, что многие проблемы, описанные в этой статье, можно решить с помощью NSDistributedNotificationCenter (developer.apple.com/library/mac/documentation/Cocoa/Reference/), позволяющий приложениям взаимодействовать друг с другом. В конце концов, я считаю, что только одно приложение должно отвечать за сохранение данных и доступ к настройкам (это приложение будет действовать как прокси между другим приложением и данными).   -  person Niels Mouthaan    schedule 05.01.2015
comment
Общие настройки можно легко настроить для набора приложений с помощью [[NSUserDefaults initWithSuiteName:]](developer.apple.com/library/prerelease/ios//documentation/Cocoa/).   -  person Sega-Zero    schedule 06.07.2015
comment
Небольшое примечание: вы можете переключаться между значениями LSUElement, используя TransformProcessType().   -  person s4y    schedule 19.05.2016


Ответы (1)


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

И демон, и приложение просмотра используют одно и то же основное хранилище данных для сохранения и извлечения данных.

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

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

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

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

Все готово: как только вы зарегистрируете демон с помощью SMLoginItemSetEnabled, launchd запустит его (при необходимости), когда программа просмотра подключится к своей службе 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 для наблюдения за изменениями в общих ключах.

person s4y    schedule 30.07.2017