В протоколе можно явным образом обозначить некоторые или все методы как необязательные.

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

Ответ на этот вопрос состоит в том, что Objective-C — не только динамический, но и интроспективный язык программирования. Объекту можно дать команду обрабатывать сообщение, фактически не посылая его. Главная роль в этом принадлежит методу respondsToSelector: из класса NSObject, который принимает селектор в качестве своего параметра и возвращает логическое значение BOOL. С помощью этого метода сообщение можно отправить объекту только в том случае, если это будет безопасно, как показано ниже.

MyClass* me = [MyClass new];

if ([тс respondsToSelector:@selector(woohoo)]) [

[me woohoo];

}

Это вряд ли стоит делать перед отправкой любого прежнего сообщения, поскольку в этом нет никакой необходимости, если только речь не идет о необязательных методах. К тому же это несколько замедляет работу приложения. На самом деле вызов метода respondsToSelector: для объектов в приложении считается в среде Cocoa чем-то само собой разумеющимся. Для того чтобы убедиться в этом, реализуйте метод respondsToSelector: в классе AppDelegate из проекта Empty Window, снабдив его средствам регистрации, как показано ниже.

- (BOOL) respondsToSelector: (SEL) sel {

NSLog(@"%@", NSStringFromSelector(sel)); return [super respondsToSelector:(sel)];

}

После запуска приложения Empty Window на своем компьютере я получил следующий результат (в нем опущены закрытые методы и многократные вызовы одного и того же метода).

application:handleOpenURL:

application:openURL:sourceApplication:annotation: applicationDidReceiveMemoryWarning: applicationWillTerminate: applicationSignificantTimeChange:

application:willChangeStatusBarOrientation:duration: application: didChangeStatusBarOr ientation: application:willChangeStatusBarFrame: application: didChangeStatusBarFrame: application:deviceAccelerated: application:deviceChangedOrientation:

applicationDidBecomeActive: applicationWillResignActive: applicationDidEnterBackground: applicationWillEnterForeground: applicationWillSuspend: application:didResumeWithOptions: application:shouldSaveApplicationState: application: supportedlnterfaceOrientationsForWindow: application:performFetchWithCompletionHandler:

application:didReceiveRemoteNotification:fetchCompletionHandler: application:willFinishLaunchingWithOptions: application:didFinishLaunchingWithOptions:

Таким образом, в среде Cocoa проверяется, какие необязательные (в том числе и недокументированные) методы протокола UIApplicationDelegate фактически реализованы в экземпляре класса AppDelegate, который явно согласился реагировать на любые сообщения от этих методов, поскольку это делегат объекта типа UIApplication, а следовательно, он формально соответствует протоколу UIApplicationDelegate. Шаблон делегата полностью полагается на данный способ (см. главу 11). Обратите внимание на правила, которым здесь следует среда Cocoa. Как только ей встретится рассматриваемый объект, в ней проверяются сразу все необязательные методы протокола и, предположительно, сохраняются результаты. Такой первоначальный единовременно совершаемый “обстрел” проверяемого объекта вызовами метода respondsToSelector: приводит к некоторому замедлению работы приложения, но, получив однажды ответы на все интересующие вопросы, среда Cocoa больше не повторяет в дальнейшем проверки того же самого объекта.


 

 

 

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