Notification
A container for information broadcast through a notification center to all registered observers.
애플 공식문서에서는 노티피케이션을 “모든 등록된 옵저버에게 브로드캐스트되는 정보의 컨테이너"라고 정의하고 있다.
NotificationCenter
라는 싱글턴 객체를 통해 이벤트 발생여부를 옵저버를 등록해 놓은 객체들에게 Notification
을 post하는 방법으로 사용할 수 있다. Notification.Name
이라는 값을 통해서 이벤트를 구분할 수 있다.
NotificationCenter
A notification dispatch mechanism that enables the broadcast of information to registered observers.
애플 공식문서에서는 “등록된 옵저버에게 정보를 브로드캐스트 할 수 있는 발송 매커니즘” 이라고 정의한다.
NotificationCenter ➡️ Notification 사용방법
NotificationCenter에 Observer 등록하기
유투브에서 원하는 채널의 구독 설정
을 하는 것과 같이, 관찰하고 싶은 이벤트를 addObserver
를 사용해서 등록해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class Son {
let name: String
var pocketMoney: Int
init(name: String, pocketMoney: Int) {
self.name = name
self.pocketMoney = pocketMoney
// NotificationCenter에 Observer 등록하기 - 구독 설정
NotificationCenter.default.addObserver(self,
selector: #selector(answerToDaddy(_:)),
name: Notification.Name.toDo,
object: nil)
@objc func answerToDaddy(_ noti: Notification) {
// notification.userInfo 값을 받아온다.
guard let object = noti.userInfo?[ToDoList.math] as? String else {
return
}
print("\(name): 오늘의 할일은 \(object)입니다.")
}
}
}
|
name
과 pocketMoney
을 프로퍼티로 가지는 Son
이라는 클라스를 만들고 초기화 시 NotificationCenter
에 Observer
를 등록한다.
1️⃣ self
: notification의 관찰자(observer)가 될 object ➡️ 여기서는 자기 자신(Son)
2️⃣ selector
: notification이 오면 실행할 함수 (등록한 이름의 노티를 받으면 answerToDaddy(_:)
를 실행한다.)
3️⃣ name
: notification의 이름 (Notification.Name("이름")
이렇게 등록하고 post와 맞춰도 된다. 여기서는 Extension으로 지정해 줌)
4️⃣ object
: 지정하면 특정 sender로부터만 notification을 받음 (optional)
1
2
3
4
|
NotificationCenter.default.addObserver(self,
selector: #selector(answerToDaddy(_:)),
name: Notification.Name.toDo,
object: nil)
|
⬆️ toDo
라는 이름의 notification을 받으면 answerToDaddy(_:)
를 실행한다.
NotificationCenter로 Post하기 (발송하기)
.post
를 사용하여 NotificationCenter로 Notification
을 보낼 수 있다.
Dad
라는 클라스에서 toDo
라는 이름으로 Notification
를 NotificationCenter
로 발송한다.
1️⃣ name
: 발송하고자 하는 notification의 이름 (이걸 통해 알림을 식별)
2️⃣ object
: 특정 sender의 notification만 받고 싶은 경우에 작성 (없으면 nil)
3️⃣ userInfo
: notification과 관련된 값 = extra data를 보내는데 사용한다. (없으면 nil)
이때 userInfo의 타입은 위에서 말했다시피 [Anyhasable : Any] 이기 때문에 다운캐스팅해서 원하는 타입에 맞춰 작성해주면 된다.
1
2
3
4
5
6
7
8
9
10
|
class Dad {
func callSon() {
print("what's your chore for Today?")
// NotificationCenter로 Post 발송
NotificationCenter.default.post(name: Notification.Name.toDo,
object: nil,
userInfo: [ToDoList.math: "수학 문제풀기"])
}
}
|
removeObserver
addObserver
이후에 removeObserver
를 사용하여 등록한 Observer
를 제거할 수 있다.
If your app targets iOS 9.0 and later or macOS 10.11 and later,
and you used addObserver(_:selector:name:object:) to create your observer,
you do not need to unregister the observer.
If you forget or are unable to remove the observer,
the system cleans up the next time it would have posted to it.
애플 문서에서는 앱이 iOS 9 이이상을 타겟으로 한다면 자동으로 옵저버를 정리해 준다고 되어 있지만, 삭제 시점이 내가 원하는 시점이 아닐 수 있으니 deinit
을 사용하여 옵저버를 제거해 주는 것이 좋다.
장 / 단점
장점
- 많은 코드를 작성할 필요 없이 구현이 비교적 간단하다.
- 일대다 방식으로 여러 객체에 쉽게 알림을 보내줄 수 있다.
- Notification과 관련된 정보를 Any? 타입의 object, [AnyHashable: Any]? 타입의 userInfo로 전달받아 사용할 수 있다.
단점
- 제어 프로세스의 추적이 어려울 수 있다.
- 등록된 개체는 알림센터에서 등록을 취소해주어야 한다.
- post한 이후의 피드백을 받을 수 없다.
- 컨트롤러와 관찰자 개체간의 연결 관리를 위해서는 제 3자 개체가 필요하다.
예제코드 풀버전
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
// extension으로 Notification Name 설정 (호출 시 용이)
extension Notification.Name {
static let toDo = Notification.Name("toDo")
static let pocketMoney = Notification.Name("pocketMoney")
}
// Notification과 관련된 인스턴스
enum ToDoList {
case math
case reading
case pushUp
}
class Dad {
func callSon() {
print("what's your chore for Today?")
// NotificationCenter로 `toDo`라는 이름의 Post 발송
NotificationCenter.default.post(name: Notification.Name.toDo,
object: nil,
userInfo: [ToDoList.math: "수학 문제풀기"])
}
func askHowMuchSonHave() {
print("How much do you Have money?")
// NotificationCenter로 `pocketMoney`라는 이름의 Post 발송
NotificationCenter.default.post(name: Notification.Name.pocketMoney,
object: nil)
}
}
class Son {
let name: String
var pocketMoney: Int
init(name: String, pocketMoney: Int) {
self.name = name
self.pocketMoney = pocketMoney
// NotificationCenter에 `toDo`라는 이름의 Observer 등록하기 - 구독 설정
NotificationCenter.default.addObserver(self,
selector: #selector(answerToDaddy(_:)),
name: Notification.Name.toDo,
object: nil)
// NotificationCenter에 `pocketMoney`라는 이름의 Observer 등록하기
NotificationCenter.default.addObserver(self,
selector: #selector(toTellDaddyHowMuchIHave(_:)),
name: Notification.Name.pocketMoney,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self,
name: Notification.Name.toDo,
object: nil)
NotificationCenter.default.removeObserver(self,
name: Notification.Name.pocketMoney,
object: nil)
}
@objc func answerToDaddy(_ noti: Notification) {
// notification.userInfo 값을 받아온다.
guard let object = noti.userInfo?[ToDoList.math] as? String else {
return
}
print("\(name): 오늘의 할일은 \(object)입니다.")
}
@objc func toTellDaddyHowMuchIHave(_ noti: Notification) {
print("\(name): 제가 가진 용돈은 \(pocketMoney)원 입니다.")
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Dad 인스턴스 생성
let jae: Dad = Dad()
// Son 인스턴스 생성 - init하면서 옵저버 등록됨
let sion: Son = Son(name: "Sion", pocketMoney: 1000)
let smith: Son = Son(name: "Smith", pocketMoney: 500)
let matthew: Son = Son(name: "Matthew", pocketMoney: 3800)
// jae가 NotificationCenter에 post 한다
jae.callSon()
jae.askHowMuchSonHave()
}
}
// what's your chore for Today?
// Sion: 오늘의 할일은 수학 문제풀기입니다.
// Smith: 오늘의 할일은 수학 문제풀기입니다.
// Matthew: 오늘의 할일은 수학 문제풀기입니다.
// How much do you Have money?
// Sion: 제가 가진 용돈은 1000원 입니다.
// Smith: 제가 가진 용돈은 500원 입니다.
// Matthew: 제가 가진 용돈은 3800원 입니다.
|
Reference
Apple - notification
Apple - notificationcenter
Apple - removeObserver(_:)
Ari - Notification, NotificationCenter
Kio - TIL
Delegate, NOTIFICATION,KVO pros and cons