Разработка пользовательского агента без графического интерфейса пользователя в Objective-C с использованием NSDistributedNotificationCenter

Я хотел бы создать пользовательский агент в Objective-C, который прослушивает уведомления по умолчанию NSDistributedNotificationCenter. Агент не будет иметь графического интерфейса. Однако когда я создаю приложение Cocoa (я также буду использовать распределенные объекты, которые, как я думаю, есть только в Cocoa) в Xcode, Xcode устанавливает проект как приложение с графическим интерфейсом.

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

Я рассмотрел возможность использования NSRunLoop из текущего NSThread, однако кажется, что NSRunLoop ждут только NSPort. Нет никакого упоминания об ожидании NSNotifications.


person Raffi Khatchadourian    schedule 14.12.2011    source источник
comment
Если вы имеете в виду NSProxy и NSDistantObject и весь этот беспорядок, это в Foundation, а не в AppKit (оба из которых являются Cocoa). Вам не нужен AppKit для распределенных объектов. Тем не менее, вы можете взглянуть на XPC. Это новое в Lion, но в зависимости от того, что вы делаете, это может быть намного проще, чем использование удаленных объектов.   -  person Jason Coco    schedule 14.12.2011
comment
@JasonCoco Спасибо за информацию. Я посмотрел на XPC. Кажется, что XPC — это способ разбить ваше приложение на отдельные процессы, так что сбой одного процесса не влияет на другой процесс. Например, если я писал приложение типа Mail.app, мне может понадобиться написать сборщик почты в одном процессе, а программу чтения почты — в другом. Если сборщик почты выйдет из строя, я все равно смогу прочитать загруженную почту. Таким было мое впечатление от использования XPC. В моем случае я пишу клиент-серверную архитектуру, и мне понадобится доступ к сети (не только IPC).   -  person Raffi Khatchadourian    schedule 14.12.2011
comment
Хорошо. В этом случае вы можете просто написать программу Foundation.   -  person Jason Coco    schedule 14.12.2011


Ответы (1)


NSDistributedNotificationCenter — это Foundation, поэтому вам не нужно создавать приложение с графическим интерфейсом. Например, вы можете создать шаблон командной строки и запустить его из терминала. В качестве очень простого примера вы можете создать пример, который просто распечатывает каждое распределенное уведомление, которое он получает ниже.

Для сборки скопируйте в шаблон Xcode для приложения командной строки Foundation или просто скопируйте в текстовый файл с именем, например test_note.m, и соберите в соответствии с комментариями. В этом примере приложение никогда не завершится (CFRunLoopRun() никогда не вернется), и вам придется убить его, нажав CTRL+C из терминала или уничтожив его чем-то вроде kill или монитором активности.

// test_build.m
// to build: clang -o test_build test_build.m -framework foundation

#import <Foundation/Foundation.h>

@interface Observer : NSObject

- (void)observeNotification:(NSNotification*)note;

@end

@implementation Observer

- (void)observeNotification:(NSNotification*)note
{
  NSLog(@"Got Notification: %@", note);
}

@end

int main (int argc, char const *argv[])
{
  @autoreleasepool {
    Observer* myObserver = [[Observer alloc] init];
    [[NSDistributedNotificationCenter defaultCenter] addObserver:myObserver selector:@selector(observeNotification:) name:nil object:nil];
    CFRunLoopRun();
  }
  return 0;
}
person Jason Coco    schedule 14.12.2011
comment
Я понимаю. Итак, в приложении Cocoa Xcode действительно спрашивает, хотите ли вы создать приложение с графическим интерфейсом. Я вполне мог бы написать приложение CLI и просто #импортировать библиотеки Cocoa, если это необходимо. Верный? - person Raffi Khatchadourian; 14.12.2011
comment
Да, в средстве выбора шаблона Xcode шаблон приложения Cocoa предназначен для приложения AppKit. Вы можете написать инструмент командной строки, который использует AppKit, но есть много предостережений, вам нужно убедиться, что вы получаете соединение с оконным сервером, чтобы некоторые вещи работали правильно, другие вещи просто не будут работать и т. д. В основном, из шаблона инструмента командной строки вы получаете все Foundation и CoreFoundation. Вы можете добавить другие фреймворки Cocoa, такие как CoreData и т. д. Если вы хотите использовать что-то из AppKit, вам нужно более внимательно изучить документацию. - person Jason Coco; 14.12.2011
comment
Это звучит неплохо. Кстати, с приведенным выше решением, будет ли это напрямую использоваться, если я запущу приложение, используя launchctl (launchd) в качестве пользовательского агента? Я прочитал эту документацию, и кажется, что они рекомендуют, чтобы приложения работали по требованию. Однако похоже, что в файле конфигурации launchd я могу указать только порт для прослушивания, в котором launchd запустит мое приложение. Однако я не уверен, как заставить это работать с NSDistributedNotificationCenter. Возможно, было бы лучше сохранить мой пользовательский агент? - person Raffi Khatchadourian; 14.12.2011
comment
Кроме того, нужен ли @autoreleasepool, если я использую ARC? - person Raffi Khatchadourian; 14.12.2011
comment
Да, launchd отдает предпочтение демонам в стиле on-demand, но это требует гораздо больше работы. В вашем случае вы можете настроить файл launchd plist для этого процесса так, чтобы launchd запускал процесс при запуске пользовательского сеанса и просто поддерживал его в рабочем состоянии (т. е. повторно запускал процесс, если он умирает или дает сбой). Это будет означать, что пользователю придется управлять запуском и остановкой приложения, используя вызовы launchctl load и launchctl unload соответственно, но это значительно упростит разработку. - person Jason Coco; 14.12.2011
comment
@RaffiKhatchadourian да, @autoreleasepool необходим, потому что некоторые библиотеки/фреймворки могут использовать или не использовать arc. В любом случае, новая версия @autoreleasepool очень быстрая и приятная, и, конечно же, ничего не испортит. - person Jason Coco; 14.12.2011
comment
Ага, думаю, я так и сделаю. Я буду держать консольное приложение в цикле и просто установлю запись plist в KeepAlive. Кроме того, я не думаю, что смогу написать демон стиля по запросу, используя NSDistributedNotificationCenter, поскольку нет способа сообщить launchd в plist, что я слушаю и когда меня разбудить. - person Raffi Khatchadourian; 15.12.2011