Книга: iOS. Приемы программирования
Обсуждение
Обсуждение
Вся эта теория станет значительно более понятной, если пояснить на примере. Мы собираемся создать класс Person и добавить к нему два свойства: имя и фамилию. Оба этих свойства будут относиться к типу NSString. Затем в делегате нашего приложения мы собираемся инстанцировать объект типа Person. Но не будем задавать имя и фамилию этой персоны, а отошлем в центр уведомлений само уведомление и его пользовательский словарь. В этом пользовательском словаре уведомления запишем имя и фамилию как элементы типа NSString. В методе инициализации класса Person мы собираемся слушать уведомление, которое приходит от делегата приложения. Затем извлечем имя и фамилию из пользовательского словаря и зададим эти значения для соответствующих свойств объекта-персоны.
Вот заголовочный файл делегата нашего приложения:
#import <UIKit/UIKit.h>
/* Имя уведомления, которое мы собираемся послать */
extern NSString *const kSetPersonInfoNotification;
/* Ключ имени в словаре пользовательской информации уведомления */
extern NSString *const kSetPersonInfoKeyFirstName;
/* Ключ фамилии в словаре пользовательской информации уведомления */
extern NSString *const kSetPersonInfoKeyLastName;
@interface AppDelegate: UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@end
А вот реализация делегата нашего приложения:
#import «AppDelegate.h»
#import «Person.h»
NSString *const kSetPersonInfoNotification = @"SetPersonInfoNotification";
NSString *const kSetPersonInfoKeyFirstName = @"firstName";
NSString *const kSetPersonInfoKeyLastName = @"lastName";
@implementation AppDelegate
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
Person *steveJobs = [[Person alloc] init];
NSNotification *notification =
[NSNotification
notificationWithName: kSetPersonInfoNotification
object: self
userInfo:@{kSetPersonInfoKeyFirstName: @"Steve",
kSetPersonInfoKeyLastName: @"Jobs"}];
/* В настоящее время класс person слушает это уведомление. Этот класс
извлечет из уведомления информацию об имени и фамилии и задаст
собственные имя и фамилию, основываясь на информации, полученной
из пользовательского словаря уведомления. */
[[NSNotificationCenter defaultCenter] postNotification: notification];
/* Вот доказательство */
NSLog(@"Person's first name = %@", steveJobs.firstName);
NSLog(@"Person's last name = %@", steveJobs.lastName);
self.window = [[UIWindow alloc]
initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Важнее всего в данном случае будет реализация класса Person (Person.m):
#import «Person.h»
#import «AppDelegate.h»
@implementation Person
— (void) handleSetPersonInfoNotification:(NSNotification *)paramNotification{
self.firstName = paramNotification.userInfo[kSetPersonInfoKeyFirstName];
self.lastName = paramNotification.userInfo[kSetPersonInfoKeyLastName];
}
— (instancetype) init{
self = [super init];
if (self!= nil){
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver: self
selector:@selector(handleSetPersonInfoNotification:)
name: kSetPersonInfoNotification
object: [[UIApplication sharedApplication] delegate]];
}
return self;
}
— (void) dealloc{
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
@end
Значение, указываемое для параметра object метода addObs erver: selector: name: object:, — это объект, от которого, как предполагается, должно поступать уведомление. Если какой-то другой объект пошлет уведомление с таким же именем, то ваш слушатель не должен будет обрабатывать это уведомление. Как правило, вы указываете такой объект в тех случаях, когда точно знаете, какой именно объект должен посылать интересующее вас уведомление. Такая возможность есть не всегда. Например, бывают очень сложные приложения, где один контроллер вида, расположенный на конкретной вкладке, должен слушать уведомления, поступающие от другого контроллера вида, находящегося на другой вкладке. При этом у слушателя может и не быть ссылки на тот экземпляр контроллера вида, откуда будет исходить уведомление. В таком случае можно передать nil параметру parameter вышеупомянутого метода.
Запустив это приложение, вы увидите на консоли следующий вывод:
Person's first name = Steve
Person's last name = Jobs
Итак, и отправка, и получение этого уведомления произошли внутри нашей программы. А что насчет системных уведомлений? Мы подробнее поговорим о них в дальнейшем. Сейчас, пока вы находитесь в Xcode, нажмите комбинацию клавиш Command+Shift+O (O — это Open (Открыть)), после чего введите UIWindow.h. Открыв этот файл заголовка, найдите в нем объект UIKeyboardWillShowNotification, а в этом объекте — такой блок кода:
// Каждое уведомление включает в себя объект nil и словарь userInfo,
// содержащий (в координатах экрана) начало и конец области, которую
// занимает на дисплее виртуальная клавиатура.
// Пользуйтесь различными возможностями convertRect, относящимися к UIView и UIWindow, чтобы получить контур клавиатуры в желаемой системе
// координат. Анимационные пары «ключ/значение» доступны лишь для
// уведомлений, относящихся к семейству «will»
UIKIT_EXTERN NSString *const UIKeyboardWillShowNotification;
UIKIT_EXTERN NSString *const UIKeyboardDidShowNotification;
UIKIT_EXTERN NSString *const UIKeyboardWillHideNotification;
UIKIT_EXTERN NSString *const UIKeyboardDidHideNotification;
Это код Apple. Мы написали наш код точно таким же образом. Apple предоставляет уведомления, отправляемые системой, а затем документирует их. Вам понадобится сделать нечто подобное. При создании уведомлений, посылаемых компонентами, находящимися внутри вашего приложения, обязательно документируйте эти уведомления и объясняйте другим программистам (в частности, коллегам, работающим с вами в одной команде), каковы типичные значения, содержащиеся в пользовательском словаре такого уведомления, а также сообщайте им всю прочую важную информацию о ваших уведомлениях.