NotificationCenter에 대해 알아 보겠습니다.
NotificationCenter
NotificationCenter의 동작에 대해 먼저 이야기 해보겠습니다.
NotificationCenter에 등록된 Event가 발생하면 해당 Event들에 대한 행동을 취하는것.
앱 내에서 아무데서나 메시지를 던지면 앱 내의 아무데서나 이 메시지를 받을 수 있게 해 주는 것이 NSNotificationCenter의 역활.
NotificationCenter는 notification의 중계자 역할을 합니다.
//NotificationCenter Singleton Pattern
NotificationCenter.default
post
post는 전송 하는 notification입니다.
myNoti를 Observer에게 전달할 값을 전달해주는 부분 입니다.
NotificationCenter.default.post(name:"myNoti", object:" 전달할 값")
Observer 등록
옵저버란 말그대로 계속 탐지하는거라고 보시면 되는데, 뭘 탐지하느냐!
name이라는 키 값을 탐지하는겁니다.
어떤 객체가 "myNoti"라는 name으로 notification을 전송 했는데 옵저버에서 탐지 하고있다가 "myNoti"가 오면 수행 하는 녀석 입니다!
NotificationCenter.default.addObserver(observer:Any, selector:Selector, name: NSNotification.Name?, object:Any?)
//구현
NotificationCenter.default.addObserver(self, selector: #selector(handleNoti(_:)), name: myNoti, object: nil)
위의 소스를 보면, myNoti라는 name의 notification이 오면 selector를 실행하라 라는 뜻입니다.
@objc func handleNoti(_ noti: Notification) {
print(noti)
print("handleNoti")
}
selector의 handleNoti를 실행하면 파라미터로 post가 넘긴 name = myNoti, object = Optional(전달할 값), userInfo = nil 값이 넘어오게 됩니다.
Remove Observer
NotificationCenter 는 싱글턴 인스턴스라서 여러 오브젝트에서 공유합니다. 그래서 옵저버를 등록한 오브젝트가 메모리에서 해제되면 NSNotificationCenter에서도 옵저버를 없앴다고 알려줘야 됩니다.
// self에 등록된 옵저버 전체 제거
notiCenter.removeObserver(self)
//옵저버 하나 제거(등록된 특정 노티를 제거하기 위해 사용)
notiCenter.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
보통은 Counterpart되는곳에 맞춰서 해제 시켜줍니다.
viewWillAppear < - > viewWillDisappear
viewdidload() < - > deinit() : 1번씩만 호출되니까
전체 코드 확인
ViewController.swift
class ViewController: UIViewController {
let notiCenter = NotificationCenter.default
var observer: NSObjectProtocol? // addObserver에 반환값이 있는 메서드를 사용할때 해제 해주어야 할 프로퍼티
override func viewDidLoad() {
super.viewDidLoad()
//object는 어떤객체를 전달할지 queue는 스레드 using은 수행할 로직.
//NSNotification.Name.UIKeyboardWillShow 키보드가 나타나기 직전에 알려줘라
// .을 사용하면 여러가지 설정이 있다.
// 시스템에서 어떤 일이 일어났을때 캐치를 하고싶을때 컨트롤하고싶을때 notification을 사용해서 알 수 있다.
notiCenter.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: .main) { (noti) in
print(noti)
print("UIKeyboardWillShow")
}
/***************************************
# 노티피케이션을 이용해서 클로저로 반환을 하면은
NSObjectProtocol라는 타입이 있기 때문에
이런식으로 NSObjectProtocol를 해제해주어야된다.
notiCenter.removeObserver(observer)
****************************************/
observer = notiCenter.addObserver(forName: NSNotification.Name.UIApplicationDidBecomeActive, object: nil, queue: .main) { (noti) in
print(noti)
print("UIApplicationDidBecomeActive")
}
//Device가 회전했는지 체크
//notiCenter.addObserver(forName: NSNotification.Name.UIDeviceOrientationDidChange, object: nil, queue: .main) { (noti) in
//print(noti)
//print("UIDeviceOrientationDidChange")
//}
notiCenter.addObserver(self, selector: #selector(deviceOrientationDidChange(_:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
//똑같은 Notification이 등록되면 중복되서 날라간다.
//notiCenter.addObserver(self, selector: #selector(deviceOrientationDidChange(_:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}
@objc func deviceOrientationDidChange(_ noti: Notification) {
print(noti)
print("deviceOrientationDidChange")
}
// 매칭되는곳에 맞춰서 해제 시켜줘야된다.viewWillAppear <-> viewWillDisappear
// viewdidload() <-> deinit() : 1번씩만 호출되니까
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
//NotificatioCenter는 싱글턴이여서 메모리가 계속 상주하기 때문에 해제를 시켜줘야된다.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
notiCenter.removeObserver(self) // self에 등록된 옵저버 전체 제거
notiCenter.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil) //옵저버 하나 제거(등록된 특정 노티를 제거하기 위해 사용)
}
@IBAction func postButton(_ sender: UIButton) {
//AnotherVC에 있는 myNoti에 송출하기 위해 사용.
NotificationCenter.default.post(name: myNoti, object: "김승진")
}
deinit {
print("deinit")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
AnotherViewController.swift
import UIKit
let myNoti = Notification.Name.init("myNoti") // 외부에서 접근 가능하도록 하기위해 클래스 위에 선언한것.
//NotiName을 설정하는 방법의 또다른 방식.
extension Notification.Name {
static let myNoti2 = Notification.Name.init("kMyNoti2")
}
class AnotherViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handleNoti(_:)), name: myNoti, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleNoti(_:)), name: Notification.Name.myNoti2, object: nil)
}
//myNoti라 Name이라는 것을 받으면 작동하는 메서드
@objc func handleNoti(_ noti: Notification) {
print(noti)
print("handleNoti")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
'iOS' 카테고리의 다른 글
[iOS] UIImagePickerController (0) | 2019.07.24 |
---|---|
[iOS] TabbarController (0) | 2019.07.24 |
[iOS] UIDocumentInteractionController (1) | 2019.07.24 |
[iOS] 앱 샌드박스(App Sandbox)와 Container Directory (1) | 2019.07.24 |
[iOS] 오토레이아웃(AutoLayout)과 Layout 개념 (0) | 2019.07.23 |