Languages/Objective-C2011.02.08 09:34
보통 비동기적으로 프로그래밍 한다고 하면 많은 분들이 쓰레드 프로그래밍을 떠올립니다. 네. pThread같이 비교적 알기쉬운 쓰레드 메커니즘을 사용하면 아주 간단하게 비동기적 프로그래밍을 할 수 있죠. 그런데 iPhone이나 iPad는 좀 더 간단한 메커니즘을 제공합니다. 쓰레드 프로그래밍을 단 한줄도 하지 않고서도, 시스템이 제공하는 쓰레드의 도움을 받아 비동기 프로그래밍을 할 수 있죠. 그리고 이렇게 프로그래밍 하면 프로그램을 구성하는 클래스 사이에 의존 관계를 꽤 간단히 끊어버릴 수 있습니다.

결론부터 이야기하자면 NSNotification을 이용하자는 것인데요. 프로그램 내의 한 모듈에서 다른 모듈로 어떤 사건의 발생을 통지하여, 보내는 쪽 클래스의 실행 궤적과 받는 쪽의 실행 궤적이 비동기적으로 동시 수행될 수 있도록 하자는 것이죠. 

NSNotification을 이용할 때 많은 분들이 [NSNotificationCenter defaultCenter]로 얻어낸 NSNotificationCenter 객체의 postNotification 메소드를 호출하는 것을 떠올리시는데, NSNotificationCenter의 클래스 레퍼런스에도 나와 있습니다만, NSNotificationCenter를 직접 이용하면 동기적인 처리밖에 안됩니다. 

A notification center delivers notifications to observers synchronously.

무슨 이야긴가 하면, postNotification을 호출하면 해당 notification에 observer로 등록한 객체의 callback 루틴이 수행 종료될 때 까지 그 자리에서 가만히 대기하고 있게 된다는 것입니다. 그러니, 비동기적으로 프로그래밍해서 어느 정도의 병행성(concurrency)을 얻고자 한다면 이렇게 프로그래밍을 하면 안되죠. 

따라서, NSNotificationQueue를 이용해야 합니다.

Notification을 날리는 쪽에서는 다음과 같이 하면 됩니다.

[[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:@"dataLoad" object:nilpostingStyle:NSPostWhenIdle];


위의 코드는 NSNotificationQueue에 "dataLoad"라는 이름의 NSNotification 객체를 넣는 코드입니다. 이 객체는 언제 notification observer에게 전달될까요? manual에 따르면, 'run loop가 idle할 때'로 되어 있습니다. NSPostWhenIdle로 지정했으니까요. 

Notification을 받을 쪽 코드는 NSNotificationCenter를 사용할 때와 같습니다. 다음과 같이 하면, "dataLoad"라는 이름의 Notification이 떴을 때 _dataLoad 메소드가 callback으로 수행되도록 할 수 있습니다.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_loadData) name:@"dataLoad" object:nil];


한가지 주의할 것은 Notification을 queue에 집어넣을 때 NSPostNow라고 하면 비동기적으로 notification이 날아가는 게 아니라 동기적으로 처리된다는 점이에요. reference에 실린 아래의 글을 인용하는 것으로, 이번 글은 마치도록 하죠.

A notification queued with NSPostNow is posted immediately after coalescing to the notification center. You queue a notification with NSPostNow (or post one with postNotification:) when you do not require asynchronous calling behavior. For many programming situations, synchronous behavior is not only allowable but desirable: You want the notification center to return after dispatching so you can be sure that observing objects have received and processed the notification. Of course, you should use enqueueNotification... with NSPostNow rather than use postNotification: when there are similar notifications in the queue that you want to remove through coalescing.


물론, 이런 질문도 있을 수 있겠어요. 그럼 그냥 NSPostNow를 써서 큐에 넣는 대신, NSNotificationCenter의 postNotification 메소드를 부르면 되지 않느냐? 그런데 그렇게 하면 유사 이벤트 병합기능을 써먹을 수 없게 되죠. NSNotificationQueue는 (위에도 적혀 있습니다만) 같은 이름의 이벤트가 큐에 들어오면 합쳐버리거든요.

신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 좋은글 잘 읽었습니다.
    그런데, nsthread 에서는 NSPostNow 외에는 호출이 안되네요..
    혹시 가능한 방법을 찾을 수 있겠습니까?

    2011.02.21 18:27 신고 [ ADDR : EDIT/ DEL : REPLY ]