Как реализовать шаблон поиска сервисов в Cocoa Touch для нескольких проектов? - PullRequest
8 голосов
/ 06 августа 2010

Это проблема, которая беспокоила меня некоторое время.Я все еще довольно новичок с некоторыми из этих шаблонов, поэтому вам придется простить меня (и исправить меня), если я неправильно использую какое-либо из этих терминов.

Моя методология

Я создал игровой движок.Все объекты в моем игровом движке используют инверсию управления для получения зависимостей.Все эти зависимости реализуют протоколы и никогда не доступны напрямую в проекте, кроме как на этапе начальной загрузки.Чтобы получить эти объекты, у меня есть концепция сервисного локатора.Задача поиска службы заключается в том, чтобы найти объект, который соответствует определенному протоколу, и вернуть его.Это очень похоже на фабрику, но она также должна обрабатывать зависимости.

Для предоставления услуг локатору службы у меня есть то, что я называю спецификаторами службы.Локатор службы знает обо всех спецификаторах службы в проекте, и когда объект запрашивается, он пытается получить экземпляр объекта, соответствующего предоставленному протоколу, от каждого из них.Этот объект затем возвращается вызывающей стороне.Что хорошо в этой настройке, так это то, что спецификатор службы также знает о локаторе службы, поэтому, если он имеет какие-либо зависимости, он просто запрашивает указатель службы для этих конкретных зависимостей.

Чтобы привести пример, у меня есть объект с именем HighScoreManager.HighScoreManager реализует протокол PHighScoreManager.В любое время, если требуется экземпляр PHighScoreManager, его можно получить, вызвав:

id<PHighScoreManager> highScoreManager = [ServiceLocator resolve: @protocol(PHighScoreManager)];

Таким образом, инверсия управления.Тем не менее, в большинстве случаев это даже не требуется, поскольку большинство классов находятся в спецификаторе службы. Если в качестве зависимости требуется PHighScoreManager, то он извлекается через локатор службы.Таким образом, у меня есть хороший плоский подход к инверсии управления.

Моя проблема

Поскольку я хочу, чтобы код из моего игрового движка был предоставлен в общий доступ, я скомпилировал его как статическую библиотеку.Это работает потрясающе для всего остального, но, кажется, немного усложняется с локатором службы.Проблема в том, что некоторые сервисы меняются в зависимости от игры.В моем примере выше счет в одной игре может быть временем, а в другой - баллами.Таким образом, HighScoreManager зависит от экземпляра PHighScoreCreator, который сообщает ему, как создать объект PScore.

Чтобы предоставить PHighScoreCreator для HighScoreManager, мне нужен спецификатор службы для моей игры.Единственный способ, которым я мог придумать, - это использовать версию отражений Какао.Покопавшись, я обнаружил, что классы можно обнаружить через NSBundle, но, похоже, нет никакого способа получить текущий пакет.Таким образом, если я хочу иметь возможность искать спецификаторы своих сервисов, мне нужно было бы скомпилировать игровую логику в отдельный пакет, а затем заставить движок найти этот пакет и загрузить его.Чтобы сделать это, мне нужно будет создать третий проект, в котором будут размещаться и код движка, и набор игровой логики, тогда как на самом деле мне бы хотелось иметь игровой проект, в котором использовалась статическая библиотека движка.

Мой реальный вопрос

Итак, после всего этого мой вопрос

  1. Есть ли лучший способ сделать то, что я пытаюсь сделать вКакао Touch, или
  2. Есть ли способ найти классы, которые соответствуют протоколу моего спецификатора сервиса из основного пакета?

Спасибо за помощь и нашли время, чтобы прочитать вопрос.

-спиральная

Ответы [ 2 ]

1 голос
/ 31 августа 2010

Звучит так, как будто вам нужно использовать функции Objective-C runtime .Сначала вы можете получить список всех доступных классов через objc_getClassList.Затем вы можете перебрать все классы и проверить, соответствуют ли они вашему протоколу с class_conformsToProtocol.Вы не должны использовать +conformsToProtocol: сообщения здесь, поскольку во время выполнения есть классы, которые не поддерживают этот селектор.

1 голос
/ 14 августа 2010

Посмотрите на:

  • + [NSBundle mainBundle];
  • + [NSBundle bundleForClass:];
  • + [NSBundle bundleWithIdentifier:];
  • + [NSBundle allBundles];
  • + [NSBundle allFrameworks];

Они позволяют программно взаимодействовать с различными пакетами во время выполнения.Если у вас есть набор для работы, есть ряд стратегий, которые вы можете использовать, чтобы найти конкретный класс (ы), который вы ищете.Например:

  1. Получить идентификатор пакета - это будет строка NSString типа @ "com.example.GameEngineClient".
  2. Преобразовать его в допустимое имя класса Objective C путем удалениявсе до последней точки, или замена всех точек подчеркиванием, или что-то еще, а затем добавление предварительно определенного имени протокола.Например, ваш протокол, приведенный выше, может привести к появлению такой строки, как @ "GameEngineClient_PHighScoreManager".
  3. Получить назначенный класс пакета для вашего протокола с помощью NSClassFromString ().

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

Среда выполнения Objective C - прекрасная вещь!

...