Делегаты и источники данных
Делегат является объектом, действующим от имени, или при взаимодействии с, другой объект, когда тот объект встречается с событием в программе. Объект делегирования часто является объектом респондента — т.е. объект, наследовавшийся от NSResponder
в AppKit или UIResponder
в UIKit — который отвечает на пользовательское событие. Делегат является объектом, который является делегированным управлением пользовательского интерфейса для того события или по крайней мере попросился интерпретировать событие специализированным способом.
Для лучше понимания значения делегации это помогает рассмотреть стандартный объект Какао, такой как текстовое поле (экземпляр NSTextField
или UITextField
) или табличное представление (экземпляр NSTableView
или UITableView
). Эти объекты разработаны для выполнения определенной роли в универсальном виде; объект окна в платформе AppKit, например, реагирует на манипуляции мышью своими средствами управления и обрабатывает такие вещи как закрытие, изменение размеров и перемещение физического окна. Это ограниченное и универсальное поведение обязательно ограничивает то, что объект может знать о том, как событие влияет (или будет влиять), что-то в другом месте в приложении, особенно когда затронутое поведение является определенным для Вашего приложения. Делегация обеспечивает путь к Вашему пользовательскому объекту для передачи специализированного поведения к стандартному объекту.
Механизм программирования делегации дает объектам шанс скоординировать их появление и состояние с изменениями, происходящими в другом месте в программе, изменения, обычно вызываемые пользовательскими действиями. Что еще более важно делегация позволяет одному объекту изменить поведение другого объекта без потребности наследоваться от него. Делегат является почти всегда одним из Ваших пользовательских объектов, и по определению он включает специализированную логику, которую универсальный и делегирующий объект не может возможно знать сам.
Как работает делегация
Проект механизма делегации прост — посмотрите рисунок 3-1. Класс делегирования имеет выход или свойство, обычно то, которое называют delegate
; если это - выход, это включает методы для установки и доступа к значению выхода. Это также объявляет без реализации, один или несколько методов, составляющих формальный протокол или неофициальный протокол. Формальный протокол, использующий дополнительные методы — функцию Objective C 2.0 — является предпочтительным подходом, но оба вида протоколов используются платформами Какао для делегации.
В неофициальном подходе протокола класс делегирования объявляет методы на категории NSObject
, и делегат реализует только те методы, в которых это имеет интерес к координированию себя с объектом делегирования или влиянием что поведение объекта по умолчанию. Если класс делегирования объявляет формальный протокол, делегат может принять решение реализовать те методы, отмеченные дополнительный, но он должен реализовать требуемые.
Делегация следует общему проекту, проиллюстрированному рисунком 3-1.
Методы протокола отмечают значительные события, обработанные или предвидевшие объектом делегирования. Этот объект хочет или передать эти события делегату или, для нависших событий, запросить ввод или утверждение от делегата. Например, когда пользователь нажимает близкую кнопку окна в OS X, объект окна отправляет windowShouldClose:
обменивайтесь сообщениями его делегату; это дает делегату возможность наложить вето или задержать закрытие окна, если, например, окно связало данные, которые должны быть сохранены (см. рисунок 3-2).
Объект делегирования отправляет сообщение, только если делегат реализует метод. Это делает это открытие путем вызова NSObject
метод respondsToSelector:
в делегате сначала.
Форма сообщений делегации
Методы делегации имеют стандартную форму. Они начинают с имени AppKit или объекта UIKit выполнение делегирования — приложение, окно, управление, и т.д.; это имя находится в нижнем регистре и без префикса «NS» или «UI». Обычно (но не всегда) это имя объекта сопровождается вспомогательным глаголом, показательным из временного состояния события, о котором сообщают. Этот глагол, другими словами, указывает, собирается ли событие иметь место («Должен» или «Быть»), или ли это только что произошло (Сделал или «Имеет»). Это временное различие помогает категоризировать те сообщения, ожидающие возвращаемое значение и тех, которые не делают. Перечисление 3-1 включает несколько методов делегации AppKit, ожидающих возвращаемое значение.
Демонстрационные методы делегации перечисления 3-1 с возвращаемыми значениями
- (BOOL)application:(NSApplication *)sender |
openFile:(NSString *)filename; // NSApplication |
- (BOOL)application:(UIApplication *)application |
handleOpenURL:(NSURL *)url; // UIApplicationDelegate |
- (UITableRowIndexSet *)tableView:(NSTableView *)tableView |
willSelectRows:(UITableRowIndexSet *)selection; // UITableViewDelegate |
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window |
defaultFrame:(NSRect)newFrame; // NSWindow |
Делегат, реализующий эти методы, может блокировать нависшее событие (путем возврата NO
в первых двух методах), или изменяют предложенное значение (индексный набор и прямоугольник кадра в последних двух методах). Это может даже задержать нависшее событие; например, делегат, реализующий applicationShouldTerminate:
метод может задержать завершение приложения путем возврата NSTerminateLater
.
Другие методы делегации вызываются сообщениями, не ожидающими возвращаемое значение и так вводящимися для возврата void
. Эти сообщения являются чисто информационными, и имена методов часто содержат, Сделал, «Будет», или некоторая другая индикация относительно выясненного или нависшего события. Перечисление 3-2 показывает несколько примеров этих видов метода делегации.
Демонстрационный возврат методов делегации перечисления 3-2 void
- (void) tableView:(NSTableView*)tableView |
mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn; // NSTableView |
- (void)windowDidMove:(NSNotification *)notification; // NSWindow |
- (void)application:(UIApplication *)application |
willChangeStatusBarFrame:(CGRect)newStatusBarFrame; // UIApplication |
- (void)applicationWillBecomeActive:(NSNotification *)notification; // NSApplication |
Существует несколько вещей отметить об этой последней группе методов. Прежде всего, вспомогательный глагол «Will» (как в третьем методе) не обязательно означает, что ожидается возвращаемое значение. В этом случае событие неизбежно и не может быть блокировано, но сообщение дает делегату возможность подготовить программу к событию.
Другое интересное место касается вторых и последних объявлений метода в Перечислении 3-2. Единственный параметр каждого из этих методов NSNotification
объект, что означает, что эти методы вызываются как результат регистрации определенного уведомления. Например, windowDidMove:
метод связан с NSWindow
уведомление NSWindowDidMoveNotification
. Важно понять отношение уведомлений сообщениям делегации в AppKit. Объект делегирования автоматически делает своего делегата наблюдателем всех уведомлений, которые он отправляет. Весь делегат должен сделать, реализовать связанный метод для получения уведомления.
Для создания экземпляра пользовательского класса делегатом объекта AppKit просто подключите экземпляр с delegate
выход или свойство в Интерфейсном Разработчике. Или можно установить его программно через объект делегирования setDelegate:
метод или delegate
свойство, предпочтительно вначале, такой как в awakeFromNib
или applicationDidFinishLaunching:
метод.
Делегация и среды разработки приложения
Объект делегирования в Сенсорном приложении Какао или Какао часто является объектом респондента, таким как a UIApplication
, NSWindow
, или NSTableView
объект. Сам объект делегата обычно, но не обязательно, объект, часто пользовательский объект, управляющий некоторой частью приложения (т.е. объект контроллера координирования). Следующие классы AppKit определяют делегата:
Платформа UIKit также использует делегацию экстенсивно и всегда реализует ее с помощью формальных протоколов. Делегат приложения чрезвычайно важен в приложении, работающем в iOS, потому что оно должно реагировать на запуск приложения, завершенный приложением, низкая память и другие сообщения от объекта приложения. Делегат приложения должен принять UIApplicationDelegate
протокол.
Делегирующие объекты не делают (и не должен) сохранять их делегатов. Однако клиенты делегирования объектов (приложения, обычно) ответственны за обеспечение, что их делегаты вокруг для получения сообщений делегации. Чтобы сделать это, им, вероятно, придется сохранить делегата в управляемом коде памяти. Эта предосторожность применяется одинаково к источникам данных, наблюдателям уведомления и целям сообщений действия. Обратите внимание на то, что в среде сборки «мусора», ссылка на делегата сильна, потому что не применяется проблема сохранять-цикла.
Некоторые классы AppKit имеют более ограниченный тип делегата, названного модальным делегатом. Объекты этих классов (NSOpenPanel
, например), выполняет модальные диалоговые окна, вызывающие метод обработчиков в назначенном делегате, когда пользователь щелкает по кнопке OK диалогового окна. Модальные делегаты ограничиваются в объеме работой модального диалогового окна.
Становление делегатом класса платформы
Класс платформы или любой другой класс, реализующий делегацию, объявляют a delegate
свойство и протокол (обычно формальный протокол). Протокол перечисляет требуемые и дополнительные методы, которые реализует делегат. Для экземпляра Вашего класса для функционирования как делегата объекта платформы это должно сделать следующее:
Установите свой объект как делегата (путем присвоения его
delegate
свойство). Можно сделать это программно или через Интерфейсного Разработчика.Если протокол формален, объявите, что Ваш класс принимает протокол в определении класса. Например:
@interface MyControllerClass : UIViewController <UIAlertViewDelegate> {
Реализуйте все требуемые методы протокола и любых дополнительных методов, в которых Вы хотите участвовать.
Определение местоположения Объектов Через Свойство делегата
Существование делегатов имеет другое программируемое использование. Например, с делегатами для двух контроллеров координирования в той же программе просто найти и связаться друг с другом. Например, объект, управляющий приложением в целом, может найти контроллер окна инспектора приложения (предполагающий, что это - текущее ключевое окно), использующий код, подобный следующему:
id winController = [[NSApp keyWindow] delegate]; |
И Ваш код может найти объект контроллера приложения — по определению, делегат глобального экземпляра приложения — путем выполнения чего-то подобного следующему:
id appController = [NSApp delegate]; |
Источники данных
Источник данных походит на делегата за исключением того, что, вместо того, чтобы быть делегированным управление пользовательского интерфейса, это - делегированное управление данных. Источник данных является выходом, сохраненным NSView
и UIView
объекты, такие как табличные представления и представления схемы, требующие источника, из которого можно заполнить их строки видимых данных. Источник данных для представления обычно является тем же объектом, действующим как его делегат, но это может быть любой объект. Как с делегатом, источник данных должен реализовать один или несколько методов неофициального протокола для предоставления представления данные, в которых это нуждается и, в более усовершенствованных реализациях, для обработки данных, которые пользователи непосредственно редактируют в таких представлениях.
Как с делегатами, источники данных являются объектами, которые должны присутствовать для получения сообщений из объектов, запрашивающих данные. Приложение, использующее их, должно гарантировать их персистентность, сохранив их при необходимости в управляемом коде памяти.
Источники данных ответственны за персистентность объектов, которые они раздают к объектам пользовательского интерфейса. Другими словами, они ответственны за управление памятью тех объектов. Однако каждый раз, когда объект представления, такой как представление схемы или табличное представление получает доступ к данным от источника данных, это сохраняет объекты, пока это использует данные. Но очень долго это не использует данные. Обычно это держится за данные только достаточно долго для отображения его.
Реализация делегата к пользовательскому классу
Для реализации делегата к пользовательскому классу завершите следующие шаги:
Объявите методы доступа делегата в своем заголовочном файле класса.
- (id)delegate;
- (void)setDelegate:(id)newDelegate;
Реализуйте методы доступа. В управляемой памятью программе, для предотвращения сохраняют циклы, метод установщика не должен сохранять или копировать делегата.
- (id)delegate {
return delegate;
}
- (void)setDelegate:(id)newDelegate {
delegate = newDelegate;
}
В собравшей «мусор» среде, где сохраняют циклы, не проблема, Вы не должны делать делегата слабой ссылкой (при помощи
__weak
введите модификатор). Для больше на сохраните циклы, см. Усовершенствованное Руководство по программированию управления памятью. Для больше на слабых ссылках в сборке «мусора», посмотрите Сборку «мусора» для Основ Какао в Руководстве по программированию Сборки «мусора».Объявите формальный или неофициальный протокол, содержащий программируемый интерфейс для делегата. Неофициальные протоколы являются категориями на
NSObject
класс. Если Вы объявляете формальный протокол для своего делегата, удостоверьтесь, что Вы отмечаете группы дополнительных методов с@optional
директива.Форма сообщений Делегации дает уведомление для именования Ваших собственных методов делегации.
Прежде, чем вызвать метод делегации, удостоверьтесь, что делегат реализует его путем отправки ему a
respondsToSelector:
сообщение.- (void)someMethod {
if ( [delegate respondsToSelector:@selector(operationShouldProceed)] ) {
if ( [delegate operationShouldProceed] ) {
// do something appropriate
}
}
}
Предосторожность необходима только для дополнительных методов в формальном протоколе или методов неофициального протокола.