Создавание приложений с многократными пакетами

Существует несколько различных причин создать приложение как многократные загружаемые пакеты и несколько различных способов сделать это. В этом разделе описывается использовать Какао для создавания приложения в модульных, динамично загружаемых компонентах.

Разработка приложений с многократными пакетами

Проектирование приложения Какао вокруг многократных загружаемых пакетов дает Вам несколько преимуществ:

Этим целям можно удовлетворить на двух иерархических уровнях — один для организации крупномасштабного приложения и другого для небольших функций:

Для получения дополнительной информации о задержанной загрузке и модуляризации, посмотрите, что Ленивый Пакет Загружает и Строит из модулей с Загружаемыми Пакетами в этом разделе.

Для получения информации о разработке и реализации сменной архитектуры, посмотрите Сменную Архитектуру и Создание Сменной Архитектуры.

Ленивая загрузка пакета

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

Можно избежать этой сложности, просто добавив методы доступа для любых экземпляров, загруженных из пакета. Метод доступа выполняет все необходимые проверки на Вас: если объект уже инициализируется, он просто возвращает его; иначе, это загружает пакет, инициализирует объект, и затем возвращает его. Остальная часть Вашего кода приложения может тогда просто использовать метод доступа использовать объект и никогда не должна волноваться, был ли объект инициализирован уже или нет.

Перечисление 1 является примером метода доступа для объекта, инициализированного лениво от основного класса пакета. Объяснение следует за перечислением.

  Метод доступа перечисления 1 для объекта инициализируется от класса загружаемого пакета

- (id)bundleObject
{
    if(!_bundleObject)                                                 // 1
    {
        NSString *bundlePath = [[[NSBundle mainBundle] builtInPlugInsPath]
                  stringByAppendingPathComponent:@"MyBundle.bundle"];  // 2
        NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];       // 3
 
        if(bundle)
        {
            Class principalClass = [bundle principalClass];            // 4
 
            if(principalClass)
            {
                _bundleObject = [[principalClass alloc] init];         // 5
            }
        }
    }
 
    return _bundleObject;                                              // 6
}

Вот то, что делает код:

  1. Проверки, чтобы видеть, если переменная экземпляра _bundleObject существует. Если это уже существует, организация if оператор пропускается.

  2. Находит путь для пакета. В этом примере трудно кодируется путь, несмотря на то, что в большинстве приложений это указано более сложным способом.

  3. Получает соответствие объекта NSBundle пути пакета. Это сообщение неявно создает объект NSBundle, если Вы уже не существуете для пакета.

  4. Если объект NSBundle допустим, получает основной класс пакета. Это сообщение лениво загружает исполняемый код пакета, если это еще не было загружено.

  5. Если основной класс существует, _bundleObject переменная экземпляра выделяется и инициализируется.

  6. Наконец, _bundleObject возвращается. Если процесс загрузки перестал работать, _bundleObject поддерживает значение nil.

Модульное исполнение с загружаемыми пакетами

Существует много причин построить Ваше приложение из модулей с загружаемыми пакетами. Можно хотеть разделить техническую разработку так, чтобы различные компоненты приложения могли быть восстановлены, не перекомпилировав целое приложение. Можно хотеть задержать загружающиеся различные компоненты приложения. Или можно хотеть сделать обоих.

Для достижения этих целей Вы, вероятно, захотите сделать один из следующих, или оба:

Следующие два раздела описывают, как выполнить эти задачи.

Связывание компонентов кода

Для создания загружаемых пакетов для компонентов кода можно или создать новый проект XCode или добавить цель к существующей. Если Вашей целью является подразделение работы разработки, Вы, вероятно, хотите отдельный проект для каждого пакета. Если Вы просто хотите задержать загружающийся код, можно просто добавить новую цель к проекту приложения.

В целом процесс следующие:

  1. Создайте пакет, содержащий компонент кода.

  2. Скопируйте пакет в «сменный» каталог комплекта приложений.

  3. Запишите приложение, чтобы загрузить и использовать код от пакета.

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

Создание пакета

Для создания загружаемого пакета необходимо сначала решить то, что кодирует этот пакет, будет содержать, и какой класс Вы хотите служить основным классом — точка входа. Как только Вы выяснили то, что Вы хотите, чтобы пакет содержал, можно разработать проект пакета или цель.

Процесс для создания проекта XCode для загружаемого пакета описан в Создании Загружаемых Пакетов.

Добавление новой цели к существующему проекту следует за подобным образцом. Вместо того, чтобы создать новый проект, однако, выполняют следующие шаги для добавления новой цели к существующему проекту:

  1. Откройте проект приложения в XCode.

  2. Выберите New Target … из Меню проектов.

  3. Выберите Bundle для целевого типа и нажмите Далее.

  4. Дайте цели имя в Поле имени Target.

  5. Гарантируйте, что Ваш проект выбран в Добавлении К всплывающему меню Проекта, и нажмите Finish.

  6. В окне проекта удостоверьтесь, что выбрана вкладка Files.

  7. Выберите свою цель из целевого всплывающего меню.

  8. Щелкните по флажкам рядом со всеми файлами, которые Вы хотите включенный в этот пакет. Удостоверьтесь, что Вы включаете Cocoa.framework в Платформах> Соединенная группа Платформ. Обязательно не включайте реализации, появляющиеся в Вашем приложении.

  9. Измените настройки для цели пакета, как описано в Изменении Настроек Target.

Копирование загружаемых пакетов к комплекту приложений

Для копирования загружаемых пакетов в комплект приложений Вы добавляете фазу сборки копии к цели приложения, копирующей загружаемый пакет в каталог «плагинов» комплекта приложений.

Для установки фазы сборки копии пройдите через следующие шаги:

  1. Добавьте созданный пакет к своему проекту на вкладке Files.

  2. Щелкните по вкладке Targets и просмотрите цель приложения.

  3. Под Фазами Сборки в целевой области выберите последнюю фазу сборки (обычно Frameworks & Libraries). Это говорит XCode, куда поместить следующую фазу сборки.

  4. Выберите New Build Phase> New Copy Files Build Phase из Меню проектов.

  5. В области Copy Files выберите Plug-ins из всплывающего меню, маркированного «Где»:.

  6. Щелкните по вкладке Files в основной области проекта.

  7. Перетащите пакет из списка файлов проекта к полю маркированные «Файлы»: в разделе Copy Files целевой области.

Теперь, когда Вы создаете свое приложение, пакет копируется в PlugIns каталог комплекта приложений, предоставляя Вам легкий доступ к нему от Вашего кода. Можно добавить дополнительные пакеты к той же фазе копии для дополнительных компонентов.

Загрузка связанного кода

Обобщенный процесс для загрузки пакетов из приложения PlugIns каталог совпадает с описанный в Загрузке Пакетов.

В приложениях, использующих небольшое количество пакетов для компонентов крупномасштабного приложения, самый простой способ получить доступ к коду через ленивый метод доступа. Ленивая Загрузка Пакета описывает, как лениво инстанцировать объекта от пакета.

Связывание Windows и контроллеров окна

Во многих приложениях окно связано с некоторым кодом для управления окном, обычно подкласс NSWindowController. NSWindowController обеспечивает встроенную функциональность для ленивой загрузки файла пера окна. Можно пойти шаг вперед и лениво загрузить код для подкласса NSWindowController, который поочередно может загрузить файл пера.

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

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

Процесс для создания пакета для окна и его связанного кода состоит из этих двух шагов:

  1. Создайте пакет, содержащий код контроллера окна и окна.

  2. Запишите код приложения, чтобы загрузить и использовать связанный контроллер окна.

Следующие подразделы описывают этот процесс подробно.

Создание пакета контроллера окна

Создание пакета для окна и связанного контроллера окна является по существу тем же, как описано в Загрузке Пакетов. Кроме того, необходимо упаковать файл пера в проекте пакета, содержащем окно и класс контроллера окна, связанный с окном.

Как только Вы имеете новый проект пакета Какао, создаете файл пера и добавляете его к Вашему проекту:

  1. Удостоверьтесь, что Ваш проект пакета открыт в XCode.

  2. Разработчик интерфейса запуска.

  3. Выберите New … из меню File.

  4. В окне Starting Point выберите Empty под группой Какао.

  5. Выберите Save As … из меню File.

  6. Перейдите на язык.lproj/ в Вашем каталоге проекта пакета, где язык является кодом языка для файла пера — например, English или en.

  7. Нажмите Save.

  8. В Добавить листе Файла выберите цель пакета под, Добавляют к Целям и нажимают Add.

Затем, создайте класс контроллера окна:

  1. Создайте подкласс NSWindowController.

  2. Добавьте любые выходы и действия, которые Вы хотите добавить к классу.

  3. Создайте исходные файлы для класса в Вашем проекте XCode.

  4. Установите Пользовательский Класс для прокси Владельца Файла к Вашему подклассу.

Теперь можно создать само окно и поднять трубку все:

  1. Добавьте новый объект окна от палитры Cocoa-Windows и создайте ее с элементами пользовательского интерфейса.

  2. Соединитесь window выход Владельца Файла к недавно создаваемому окну и добавляет любые другие соединения, которые необходимо сделать между контроллером и элементами пользовательского интерфейса.

Наконец, запишите код для класса контроллера окна в XCode. Один требуемый метод говорит NSWindowController что файл пера использовать:

- (NSString *)windowNibName
{
    // Replace MyWindowController with the name of your window
    return @"MyWindowController";
}

Запись кода приложения

Как с другими компонентами кода, к пакетам контроллера окна лучше всего получают доступ через ленивые методы доступа. Перечисление 2 показывает реализацию для такого метода.

  Метод доступа перечисления 2 для связанного контроллера окна

- (NSWindowController *)bundledWindowController
{
    // Assume _bundledWindowController is a private instance variable
    // of type id or NSWindowController *.
    if(!_bundledWindowController)
    {
        NSString *bundlePath = [[[NSBundle mainBundle] builtInPlugInsPath]
                         stringByAppendingPathComponent:@"MyBundle.bundle"];
        NSBundle *windowBundle = [NSBundle bundleWithPath:bundlePath];
 
        if(windowBundle)
        {
            Class windowControllerClass = [windowBundle principalClass];
            if(windowControllerClass)
            {
                _bundledWindowController = [[windowControllerClass
                                                              alloc] init];
            }
        }
    }
 
    return _bundledWindowController;
}

Остальная часть Вашего кода приложения должна использовать метод доступа относиться к объекту. Например, эта строка кода показывает окно:

[[self bundledWindowController] showWindow:self];

Неявный в этом примере потенциально две ленивых операции загрузки. Во-первых, код для контроллера окна загружается когда principalClass сообщение отправляется. Кроме того, файл пера окна загружается когда showWindow: сообщение отправляется.