티스토리 뷰

저는 언제나 비동기 작업들이 골치 아픈데 hoxy... 여러분도 그러신가요?
비단 통신단에서 뿐만 아니라 앱 곳곳에서 발생하는 이벤트들도 모두 비동기적으로 발새합니다.
RxSwift와 Combine을 통해 비동기 프로그래밍을 한다면 수월하게 해격할 수 있겠지만
오늘은 더 베이직한 방법 중 하나를 골라 이야기를 해보려고 합니다.

 

서로 다른 객체 간 소통이 이루어질 때 3가지 패턴 중 하나를 주로 사용합니다.

•Notification

•Delegation

•KVO

오늘은 이 중에서도 Notification을 골라봤습니다!

글을 시작하기 전에...

Swift3 이전까진 NSNotificationCenter라고 불렸습니다.
그래서 StackOverflow나 Medium 등 예전 글에서는 NSNotificationCenter라고 적혀있습니다.

그리고... Notification Center 얘 아닙니다...?

 

Notification Center 개요

NotificationCenter를 사용하면  A객체에서 B객체에게 다양한 정보를 줄 수 있습니다.
Pub-Sub 패턴을 통해 중심의 Notification Center에 등록되어 있는 observer들에게 notification이 들어오면 알려줍니다.
NotificationCenter를 구성하는 3개의 요소들과 동작방식을 알아보겠습니다!

3개의 구성요소

• Observer : Notification을 듣고 있는 친구 (ex. B)

• Sender : Notifcation을 보낼 친구 (ex. A)

• NotificationCenter

동작방식

아래 그림 하나로 NotificationCenter를 다 설명할 수 있을 것 같아요!

 

동작 방식을 노란색 번호 순으로 살펴보도록 할게요.

1. addObserver : 우체부 아저씨는 중앙 우체국에게 '제가 서래마을로 가는 우체부입니다'라고 등록을 합니다.

2. event 발생 : 스위리가 서래마을에 사는 K군에게 보낼 A편지를 썼습니다.

3. post : 스위리가 중앙 우체국에 편지를 부쳤습니다.

4. notify : 중앙 우체국은 서래마을에 가는 우체부 아저씨에게 편지가 왔다고 전달해줍니다.

5. selector function : 아저씨가 K군에게 갈 편지를 배송해주십니다.

 

이 모든 과정에서 스위리와 우체부 아저씨는 서로를 알 필요가 없습니다. Decoupled 되어 있는 상태죠.
그리고 예시에서는 A와 B를 사람으로 의인화 했지만 실제로는 어떤 class여도 무관합니다.
ViewController일 수도, custom class, data model 무엇이나 될 수 있습니다.

📮Observer 등록하기 : 제가 우체부입니닷!

extension Notification.Name {
	static let didSendLetter = Notification.Name("didSendLetter")
  static let didReceiveTask = Notification.Name("didReceiveLetter")
}

NotificationCenter.default.addObserver(
     self, 
     selector: #selector(onDidSendLetter(_:)), 
     name: .didSendLetter, 
     object: nil)

@objc func onDidSendLetter(_ notification: Notification) {
      // do something
}

addObserver의 원형은 addObserver(_:selector:name:object:) 이고 각 parameter는 다음을 의미합니다.

  • observer (unnamed) : 해당 notification을 받고 싶어하는 객체
  • selector : notification을 받으면 실행할 메소드
  • name : 받고 싶은 notification의 이름
  • object (optional) : notification을 보내는 대상 중 받고 싶은 대상을 특정

그래서 위에 적은 코드를 말로 풀어보면, 현재 객체(self)가 didSendLetter라는 이름을 가진 notification을 받으면 onDidSendLetter 메소드를 호출하겠다는 의미입니다.

언제 addObserver를 해야할까?

중요한 질문입니다. 위에 나타낸 그림에서도 제일 먼저 일어나는 action이 addObserver였죠?
다른 객체가 post를 하기 전에 등록을 해 놓아야 그 notification을 받을 수 있기 때문입니다.
따라서 addObserver는 받고자 하는 notification이 발생하기 전에 등록해야 합니다.

 

보통 View Controller의 경우 viewDidLoadviewWillAppear에서 등록을 하게 되는데요.
등록도 중요하지만 삭제하는 것도 중요합니다. 없는 객체에 message를 보내면 안되잖아요?
서래마을로 가는 우체부 아저씨 은퇴하셨는데 그것도 모르고 서래마을로 가는 편지 부치면 영영 못간다구...
그래서 removeObserver(_:name:object)deinit이나 viewWillDisappear에 둡니다.
만약 한 번에 모든 observer를 삭제하고 싶다면 removeObserver(_:)를 쓰면 됩니다.

 

Notification.default?

default notification center를 뜻합니다.
키보드가 내려갔음을 감지하는 keyboardDidHideNotification과 같은 system notification들이
모두 default notification center에 있습니다.

 

물론 직접 notification center를 생성할 수도 있습니다. NotificationCenter에 notification이 도착하면
보내줘야 할 observer들을 판단하기 위해 등록 된 observer들을 전체적으로 훑기 때문에 성능에
문제가 생길수도 있습니다.
그렇기 때문에 성능 향상을 위해 적절히 notification center 객체를 추가 생성하면 됩니다.
(중앙 우체국 뿐만 아니라 관할 우체국이 있는 것 처럼)

💌 Post 보내기 : 편지 보내주세요

extension Notification.Name {
	static let didSendLetter = Notification.Name("didSendLetter")
  static let didReceiveTask = Notification.Name("didReceiveLetter")
}

NotificationCenter.default.addObserver(
     self, 
     selector: #selector(onDidSendLetter(_:)), 
     name: .didSendLetter, 
     object: nil)

@objc func onDidSendLetter(_ notification: Notification) {
      // do something
}

post의 원형은 post(name:object:userInfo:)이고 각 parameter는 다음을 의미합니다.

 

• name : 보낼 Notification Name

•object : Notification을 보내는 객체. addObserver에서 optional 값을 받던 object에서 지정하는 객체가 post를 보내는 대상

•userInfo : Notification에 실어 보낼 추가 정보

userInfo 사용 예시

이벤트와 함께 넘기고 싶은 정보가 있다면 이곳에 넣어 보내면 됩니다.
단, userInfo는 [AnyHashable: Any]? 타입이라 key 값이 AnyHashable인지 확인해야 합니다.
즉, custom 객체의 정보를 싣고 싶다면 Hashable protocol을 채택해서 추가 구현해야 해요.

 

그러면 observer가 userInfo를 어떻게 꺼내 쓸 수 있을까요? 아래 코드처럼 짤 수도 있고
어차피 dictionary니 key값을 확실히 알고 있다면 userInfo를 casting한 후 userInfo[key]로 활용해도 되겠죠?

 

@objc func onDidReceiveScore(_ notification: Notification) {
   if let data = notification.userInfo as? [String: Int] {
      for (name, score) in data {
         print("\(name) scored \(score) points!")
      }
   }
}

Reference

• Apple Archive : Notification Center [바로가기]

 

• Learn AppMaking.com : Using Notification Center in Swift [바로가기]

• Tistory : NotificationCenter - 관찰해서 알려주는 역할 (Dana) [바로가기]

'iOS' 카테고리의 다른 글

[iOS] iOS 면접 질문 정리  (0) 2021.10.11
[iOS] lazy var : 메모리 세이버 🦸‍♀️  (4) 2021.07.28
[iOS] Update Cycle: 뷰 업데이트 메소드  (0) 2021.07.11
[Rx] Reusable Cell의 흔적이 남는다  (0) 2021.05.17
[Rx] DisposeBag  (0) 2021.05.17
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함