본문 바로가기

개발/App Developer

Notification

복사 http://ebcban.blog.me/30089133519

통보는 하나 이상의 객체가 어떤 이벤트를 받고 싶을때 사용한다. 델리게이트가 1:1 관계로 객체간에 긴밀하게 연결되어 있다면, 통보 서비스는 동적으로 임의적인 객체간의 연결이 가능하다.

어떤 객체가 관심 있는 이벤트에 대해서 통보를 받기 위해서는 통보 센터에 자신을 등록해야 한다. 다음 코드를 보자.

01: [[NSNotificationCenter defaultCenter] 
02: addObserver:self 
03: selector:@selector(launchFinished:) 
04: name:UIApplicationDidFinishLaunchingNotification 
05: object:nil];

위 코드는 임의의 객체가 UIApplicationDidFinishLaunchingNotification 라는 통보를 발생시키면 self 객체의 launchFinished 를 호출하도록 한다. 코드의 2행과 3행의 인자는 통보가 발생했을 때 호출할 메서드를 지정한다. 여기서 이벤트는 문자열로 구분된다. 그래서 UIApplicationDidFinishLaunchingNotification 도 문자열로 정의되어 있다.

5행의 object 인자는 감시할 개체를 지정하기 위한 것이다. 만약 nil 을 지정하면 모든 객체를 대상으로 이벤트를 감시하게 된다. 만약 5행의 object 를 nil 로 설정하지 않고 특정 객체를 지정해 주면, 그 객체가 일치하는 문자열의 통보를 발생시킬 때만 통보를 받을 수 있다.

통보 이벤트를 더이상 감시할 필요가 없을때는 다음과 같이 제거해야 한다.

01: [[NSNotificationCenter defaultCenter] removeObserver:self];

removeObserver 메서드로 자신(self)이 더이상 통보를 받지 않겠다고 설정한다.

<그림1> 도움말 문서의 통보 항목

클래스의 도움말 문서를 보면 그 클래스가 발생시키는 통보를 확인 할 수 있다. 예를들어 그림1과 같이 UIWindow 클래스의 도움말을 보자. Notifications 라는 항목으로 자신이 발생시키는 통보에 대해서 설명하고 있다. UIWindowDidBecomeVisibleNotification 와 같은 통보 이름은 클래스의 헤더파일에 문자열로 정의되어 있다.

만약 직접 작성한 클래스에서 통보를 발생시키고 싶다면 어떻게 할까 ? 무척간단하다.

01: [[NSNotificationCenter defaultCenter] 
02: postNotificationName:@"myEventOccured" object:self];

NSNotificationCenter 의 postNotificationName 메서드를 이용하면 된다. object 인자는 누가 이 통보 이벤트를 발생시키는 지를 설정한다.

<그림2> 예제

그림2의 예제를 직접 구현해 보자. ObjectA,ObjectB,ObjectC 는 각각 event1, myEventOccured,모든 통보 이벤트(nil) 에 관심이 있다.

01: [[NSNotificationCenter defaultCenter] 
02: addObserver:ObjectA 
03: selector:@selector(myEventHandler:) 
04: name:@"event1" 
05: object: nil]; 
06: 

01: [[NSNotificationCenter defaultCenter] 
02: addObserver:ObjectB 
03: selector:@selector(myEventHandler:) 
04: name:@"myEventOccured" 
05: object: nil]; 
06:

01: [[NSNotificationCenter defaultCenter] 
02: addObserver:ObjectC 
03: selector:@selector(myEventHandler:) 
04: name: nil 
05: object: nil]; 
06:

ObjectC 는 name에 nil 을 설정했기 때문에 모든 이벤트를 통보받게 된다. 이제 객체X가 통보를 발생시킨다.

01: [[NSNotificationCenter defaultCenter]

02: postNotificationName:@"myEventOccured"

03: object:ObjectX

04: userInfo:[NSDictionary dictionaryWithObject:@”value1” forKey:@”data1”]

05: ];

위 코드가 실행되면 통보 센터는 ObjectX 에서 myEventOccured 통보가 발생했기 때문에, 이 통보를 감시하는 모든 객체의 메서드를 호출해 준다. 이때 감시 객체들은 ObjectX가 전달한 userInfo 딕셔너리 객체도 사용할 수 있다. 이벤트를 통보받는 메시지를 구현해 보자.

01: - (void) myEventHandler:(NSNotification *) notif 
02: { 
03: NSLog(@“%@ from %@”, [notif name], [notif object]); 
04: NSDictionary *userInfo = [notif userInfo]; 
05: // userinfo 딕셔너리의 내용을 나열하자. 
06: for (NSString *key in userInfo) { 
07: NSLog(@“%@ = %@”, key, [userInfo objectForKey:key]; 
08: } 
09: }

통보를 받으면 호출되는 이 메서드는 인자로 NSNotification 객체를 받는다. 이 객체는 통보에 대한 정보를 담고 있다. userInfo 속성은 통보를 보내는 객체가 추가 정보를 전달할 때 이용된다.

* 통보 큐

통보를 발생시킬때 호출하는 postNotificationName 메서드는 곧바로 모든 감시자의 메서드를 호출한다. 하지만 통보 큐를 이용하면 쓰레드가 유휴(Idle) 상태 일 때 메서드를 호출하게 만들 수 있다. 다음 코드를 보자.

01: [[NSNotificationCenter defaultCenter] 
02: addObserver:objectA 
03: selector:@selector(eventHandler:) 
04: name:@"appLaunched" object:nil]; 
05: 
06: [[NSNotificationQueue defaultQueue] 
07: enqueueNotification:[NSNotification 
08: notificationWithName:@"appLaunched" 
09: object:self] 
10: postingStyle:NSPostWhenIdle];

10행의 NSPostWhenIdle 옵션은 현재 쓰레드가 유휴상태일때 통보를 보내도록 한다.