При загрузке nib-файла, когда возникают его экземпляры, существует одна проблема: эти экземпляры бесполезны.

Экземпляр не используется, пока вы не сошлетесь на него (этому вопросу посвящен раздел в главе 5). Если на экземпляры нет ссылок, то они никак не используются: их нельзя включить в интерфейс; их невозможно модифицировать или конфигурировать; фактически их невозможно использовать, и они могут быстро исчезнуть, не принеся никакой пользы.

Один из основных способов решения этой проблемы — использование выходов. Выход (outlet) — это сущность в nib-файле, которая представляет собой связь от одного объекта в nib-файле к другому. Эта связь имеет направление: именно поэтому я использую предлоги “от” и “к”. Один из этих объектов называется источником (source), а другой — целью (destination) выхода. Выход имеет два аспекта.

 

Имя выхода

В nib-файле выход имеет имя, которое по существу представляет собой строку.

 

Переменная экземпляра в классе источника

Класс объекта источника выхода имеет переменную экземпляра (или set-метод), соответствующую имени выхода (в соответствием с правилами кодирования ключ-значение, обсуждавшимися в главе 5).

При загрузке nib-файла происходит нечто невероятно интеллектуальное. Объект источника и объект цели больше не являются потенциальными объектами в nib-файле; они

становятся реальными, полноценными экземплярами. Имя выхода немедленно используется по правилам кодирования ключ-значение для сравнения с переменной экземпляра (или set-методом) в объекте источника, и ей присваивается объект цели.

Например, допустим, что мы создали nib-файл, в котором класс Nib Ob j ect А имеет имя Dog, и предположим, что класс Dog имеет главную переменную экземпляра класса Person. Пусть класс Nib Object В — это класс Person. Тогда произойдет следующее.

  1. Допустим, в nib-редакторе вы рисуете линию, соединяющую объект класса Nib Object А (потенциальный экземпляр класса Dog) с объектом класса Nib Object В (потенциальным экземпляром класса Person), — этот выход называется master. Эта связь теперь становится частью nib-файла.
  2. Запустим приложение, которое загружает этот nib-файл (одним из описанных ранее способов).
  3. Создаются объекты классов Nib Ob j ect А и Nib Ob j ect В. Теперь у нас есть реальные экземпляры классов Dog и Person.
  4. Однако загрузка nib-файла не завершена. В данный момент nib-файл содержит выход от объекта класса Nib Object А к объекту класса Nib Object В с именем master. Соответственно, он вызывает метод setValue: f огКеу: из экземпляра класса Dog, в котором ключом является строка @"master", а значением — экземпляр класса Person. Теперь экземпляр класса Dog имеет ссылку на экземпляр класса Person — а именно, ссылается на значение переменной экземпляра master!

Подведем итоги: выход в nib-файле — это просто имя, связывающее два потенциальных объекта. Однако при загрузке nib-файла эти объекты становятся реальными, а выход превращается в реальную ссылку одного объекта на другой с помощью переменной экземпляра (рис. 7.7).

 

 Как выход обеспечивает ссылку на объект, созданный в nib-файле

Рис. 7.7. Как выход обеспечивает ссылку на объект, созданный в nib-файле

 

Механизм загрузки nib-файла не создает переменную экземпляра — т.е. после создания объекта источника он не содержит переменную экземпляра с корректным именем, если она не существовала ранее. Класс, которому принадлежит объект источника, должен заранее определить переменную экземпляра (или set-метод). Таким образом, для того чтобы выход работал, необходимо выполнить предварительную работу в двух местах: в классе источника и в nib-файле. Это довольно сложно. Как мы увидим, среда Xcode существенно облегчает процесс создания выхода, если класс источника не имел необходимой переменной экземпляра. Однако в этом процессе все же легко запутаться, поэтому я объясню его позже.

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

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

 

  • В сцене раскадровки прокси-объект владельца nib-файла является контроллером представления верхнего уровня. Это первый объект, указанный для сцены в структуре документа, и первый объект, который показан в доке сцены.
  • В файле . xib прокси-объект владельца nib-файла — это первый объект, показанный в структуре документа или в доке; он указывается под шаблонами Placeholders как File’s Owner.

 

Прокси-объект владельца nib-файла — это прокси-экземпляр, который уже существует за пределами nib-файла в момент его загрузки. При загрузке nib-файла этот объект не создается; он уже существует. Таким образом, реальный, уже существующий экземпляр заменяется прокси-экземпляром, который осуществляет все его связи.

Например, допустим, что в нашем nib-файле существует nib-объект класса Person, а не nib-объект класса Dog. Классом прокси-объекта владельца nib-файла является класс Dog — причем, как вы помните, класс Dog содержит переменную экземпляра master. В nib-редакторе можно провести связь от объекта владельца nib-файла (потому что он относится к классу Dog) к nib-объекту класса Person. При загрузке nib-файла механизм его загрузки сравнит прокси-объект владельца nib-файла класса Dog с уже существующим экземпляром класса Dog и назначит объект класса Person в качестве значения его переменной экземпляра master.

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

 

Выход из объекта прокси владельца nib-файла

Рис. 7.8. Выход из объекта прокси владельца nib-файла

 

Каким образом назначается владелец nib-файла? Существуют два способа.

  • Если код загружает nib-файл, вызывая методы loadNibNamed:owner:options: или instantiateWithOwner: options:, то объект владельца задается аргументом owner:.
  • Если экземпляр контроллера представления загружает nib-файл автоматически, чтобы получить свое главное представление, то контроллер представления сам назначается объектом владельца nib-файла.

Рассмотрим второй вариант, потому что мы уже создали два проекта, использовавших этот способ. Контроллер имеет главное представление. Формально это выражается тем фактом, что класс UlViewController имеет свойство view, т.е. он имеет переменную экземпляра представления или соответствующий метод доступа (или и то и другое). Когда контроллер загружает nib-файл, чтобы получить свое главное представление, он играет роль владельца этого nib-файла.

Итак, теперь понятно, каким образом контроллер, загружающий nib-файл с его главным представлением, может ссылаться на него и что-то с ним делать (например, включать в интерфейс) — он делает это с помощью переменной экземпляра представления, соответствующего

выходу представления в nib-файле. Эта ситуация похожа на рис. 7.8, на котором показан экземпляр класса Dog, владеющий nib-файлом, содержащим прокси-объект владельца nib-файла класса Dog, у которого есть выход master на объект класса Person, — за исключением того, что теперь у нас существует экземпляр класса UlViewController, содержащий прокси-объект владельца nib-файла класса UlViewController, у которого есть выход view на объект класса UlView. (Говоря “объекты класса UlViewController и UlView”, я, разумеется, имею в виду также их подклассы.)

Итак, если предполагается, что nib-файл содержит главное представление контроллера, то должны выполняться два условия.

  • Прокси-объект владельца nib-файла, находящийся в этом nib-файле, должен относиться к классу UlViewController или его подклассу — предпочтительно к классу контроллера представления, загружаемого из данного nib-файла.
  • Этот nib-файл должен содержать выход view из прокси-объекта владельца nib-файла к объекту главного представления.

Если оба эти условия выполняются, все будет хорошо. Когда контроллеру понадобится его представление, он загрузит nib-файл в качестве его владельца; в этом случае будет создан полноценный экземпляр представления, описанного в nib-файле, и переменная view контроллера представления станет ссылкой на него. Это решает нашу проблему. Все другие экземпляры, создаваемые из nib-файла, зависят от Главного представления (как его вложенные представления и т.п.), и именно переменная экземпляра view в контроллере теперь служит ссылкой на главное представление и все зависящие от него экземпляры. Теперь контроллер готов загрузить свое представление в интерфейс.

Если посмотреть на проекты, созданные в главе 6, то вы увидите, что их nib-файлы действительно организованы так, как я описал выше! Сначала посмотрим на проект Empty Window. Откроем файл Main . storyboard. Он содержит одну сцену, в которой прокси-объектом владельца nib-файла является объект View Controller. Выберите пункт View Controller в структуре документа. Переключитесь в окно инспектора идентичности. Он сообщает нам, что прокси-объект владельца nib-класса относится к классу ViewController. Теперь перейдите в окно инспектора связей. Он сообщает нам, что существует выход Outlet на объект View (если вы остановите курсор мыши над линией выхода, то объект View на канве будет выделен, чтобы облегчить его идентификацию).

Теперь посмотрим на проект Truly Empty. Откройте файл ViewController. xib. Прокси-объектом владельца nib-файла является шаблон File’s Owner. Выберите его. Перейдите в окно инспектора идентичности. Он сообщает нам, что прокси-объект владельца nib-класса относится к классу ViewController. Перейдите в окно инспектора связей. Он сообщает нам, что существует выход Outlet на объект View.


 

 

 

Добавить комментарий