Для того чтобы специально настроить поведение экземпляра класса Cocoa посредством делегирования, следует выбрать в прикладном коде класс, в котором при необходимости объявляется соответствие протоколу, подходящему для делегирования.

При выполнении приложения в свойстве delegate (или под другим аналогичным именем) экземпляра класса Cocoa задается экземпляр класса из прикладного кода. Это можно сделать как в самом прикладном коде, так и в nib-файле, установив связь с выходом delegate (или под другим аналогичным именем) соответствующего экземпляра, который должен служить в качестве делегата. Помимо обязанностей делегата для экземпляра класса Cocoa, класс делегата может выполнять и другие функции. Замечательная особенность делегирования состоит, в частности, в том, что оно оставляет место для внедрения кода делегата в архитектуру класса прикладного кода.

Рассмотрим простой пример, в котором используется предупреждающее представление типа UIAlertView. Если в этом представлении выбрана кнопка Cancel, то оно удаляется с экрана. Если же требуется выполнить еще что-нибудь в ответ на удаление предупреждающего представления, то ему нужно предоставить делегат, чтобы получить событие (alertview: d idDismissWithButtonlndex:), уведомляющее об удалении данного представления. Делегат настолько часто предоставляется предупреждающему представлению типа UIAlertView, что специально назначаемый для него инициализатор разрешает это делать. Как правило, в качестве делегата служит экземпляр (self), вызывающий прежде всего предупреждающее представление, как показано ниже.

- (void) gameWon {

UIAlertView* av =

[[UIAlertView alloc] initWithTitle:@"Congratulations!"

}

message:@"You won the game. Another game?" delegate:self cancelButtonTitle:@"No, thanks." otherButtonTitles:@"Sure!", nil];

[av show];

(void) alertView:(UIAlertView*) av didDismissWithButtonlndex:             (NSInteger)           ix             (

if (ix == 1) { // пользователь согласился еще поиграть [self newGame];

)

)

У общего для приложения экземпляра ([UIApplication sharedApplication]) имеется свой делегат, выполняющий настолько важную роль в приложении, что он автоматически предоставляется в шаблонах приложений, разрабатываемых в среде Xcode. Как пояснялось в главе 6, приложение запускается на выполнение при вызове метода UIApplicationMain, как показано ниже.

int main(int argc, char *argv[])

{

@autoreleasepool {

return UIApplicationMain(argc, argv, nil,

NSStringFromClass([AppDelegate class]));

}

}

В шаблоне проекта предоставляются файлы, в которых определяется класс AppDelegate. В приведенном выше фрагменте кода методу UIApplicationMain предписывается получить экземпляр класса AppDelegate и сделать его делегатом общего для приложения экземпляра, который также создан. Как пояснялось в главе 10, в классе AppDelegate формально принят протокол UIApplicationDelegate, а это означает, что он готов служить в качестве делегата. Там же упоминалось, что метод respondsToSelector: посылается затем делегату приложения, чтобы выяснить, какие именно методы протокола реализованы в нем. Так, если в нем реализован метод application: didFinishLaunchingWithOptions:, ему будет послан именно этот метод, предоставляющий прикладному коду одну из самых первых возможностей для выполнения.

 

Методы делегата из класса UIApplication предоставляются также в виде уведомлений. Это дает возможность экземпляру, отличающемуся от делегата приложения, быть в курсе событий, происходящих во время действия приложения, если только он зарегистрируется для их получения. Аналогичным образом в ряде других классов предоставляются дублирующие события. Например, метод делегата tableView: didSelectRowAtlndexPath: из класса UITableView соответствует уведомлению UITableViewSelectionDidCha ngeNotification.

 

В именах многих методов делегата из среды Cocoa принято употреблять модальные глаголы should (должен), will (будет) или did (сделал). Так, сообщение типа will посылается делегату перед тем, как что-нибудь произойдет; а сообщение типа did — после того, как что-нибудь произойдет. Метод типа should имеет особое назначение: он возвращает логическое значение BOOL, в ответ на которое предполагается получить логическое значение YES, разрешающее сделать что-нибудь, или логическое значение N0, запрещающее что-нибудь.

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

Зачастую свойство управляет некоторым общим поведением, тогда как сообщение делегата позволяет видоизменить это поведение в зависимости от обстоятельств во время выполнения. Например, свойство scrollsToTop управляет быстрой прокруткой представления вверх, как только пользователь коснется строки состояния. Но, даже если это свойство имеет логическое значение YES, подобное поведение можно запретить для конкретного вида касания экрана, если возвратить логическое значение N0 из метода делегата scrollViewShouldScrollToTop:.

В поисках документации на способы уведомления о наступлении некоторых событий обращайтесь за справкой к соответствующему протоколу делегата, если таковой имеется. Так, если требуется выяснить, когда именно следует начинать редактирование в поле типа UITextField, которого пользователь коснулся, вы вряд ли найдете что-нибудь, связанное с этим событием, в документации на класс UITextField. На самом деле вам следует искать описание метода textFieldDidBeginEditing: в документации на протокол UITextFieldDelegate. Если требуется отреагировать на перестановку пользователем элементов на панели закладок, то за справкой следует обращаться к документации на протокол UITabBarControllerDelegate. И так далее...


 

 

 

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