타입끼리의 Communication이 있어야 하지만, Coupling이 강해지는 것이 싫어질 경우 사용하는 방법이다. 해당 방법들은 MVVM
패턴에서 Binding
을 하는 과정에도 많이 사용됨으로 반드시 알아야만 한다
일단 바로 공식문서를 살펴보면
A container for information broadcast through a notification center to all registered observers.
그러니깐, Notification은 "알림 센터를 통해 등록된 모든 관찰자에게 브로드캐스트되는 정보 컨테이너"라고 한다.
주요 프로퍼티를 보면
init(name: Notification.Name, object: Any? = nil, userInfo: [AnyHashable : Any]? = nil)
name : 알림을 식별하는 태그
object : 발송자가 옵저버에게 보내려고 하는 객체, 주로 발송자 객체를 전달하는 데 쓰임
userInfo : 노티피케이션과 관련된 값 또는 객체의 저장소(Dictionary)
추가 정보 : 이름을 등록할 때 다음과 같이하면 효율적이다
extension Notification.Name {
static let changeLabel = Notification.Name("changeLabel")
}
import Foundation
class Teacher {
func callStudent() {
NotificationCenter.default.post(name: NSNotification.Name.hey,
object: nil,
userInfo: [NotificationKey.iam: "I'm"])
}
}
class Student {
let name: String
init(name: String) {
self.name = name
NotificationCenter.default.addObserver(self,
selector: #selector(answerToTeacher(noti:)),
name: Notification.Name.hey, object: nil)
}
@objc func answerToTeacher(noti: Notification) {
guard let height = noti.userInfo?[NotificationKey.iam] as? String else {
return
}
print("\(height) \(name)")
}
}
extension Notification.Name {
static let hey = Notification.Name("hey")
}
enum NotificationKey {
case iam
}
let yagom = Teacher()
let kane = Student(name: "kane")
let james = Student(name: "james")
let tak = Student(name: "tak")
yagom.callStudent()
//I'm kane
//I'm james
//I'm tak
Notification Center 는 등록된 옵저버에게 동시에 노티피케이션을 전달하는 클래스이다. NotificationCenter 클래스는 노티피케이션을 발송하면 노티피케이션 센터에서 메세지를 전달한 옵저버의 처리할 때까지 대기한다. 즉, 흐름이 동기적(synchronous)으로 흘러간다. 노티피케이션을 비동기적으로 사용하려면 NotificationQueue를 사용하면 된다.
A notification dispatch mechanism that enables the broadcast of information to registered observers.
Notification Center
얻기 func addObserver(_ observer: Any, selector aSelector: Selector, name aName: NSNotification.Name?,object anObject: Any?)
func removeObserver(_ observer: Any, name aName: NSNotification.Name?, object anObject: Any?)
func removeObserver(_ observer: Any)
Notification을 만들어서 발송!!!!
func post(_ notification: Notification)
func post(name aName: NSNotification.Name, object anObject: Any?, userInfo aUserInfo: [AnyHashable: Any]? = nil)
func post(name aName: NSNotification.Name, object anObject: Any?)
import Foundation
class Teacher {
func callStudent() {
let noti = Notification(name: Notification.Name.hey)
NotificationCenter.default.post(noti)
}
}
class Student {
let name: String
init(name: String) {
self.name = name
NotificationCenter.default.addObserver(self,
selector: #selector(answerToTeacher(noti:)),
name: Notification.Name.hey, object: nil)
}
@objc func answerToTeacher(noti: Notification) {
print("Ok Teacher I'm coming. My name is \(name)")
}
}
extension Notification.Name {
static let hey = Notification.Name("hey")
}
let yagom = Teacher()
let kane = Student(name: "kane")
let james = Student(name: "james")
let tak = Student(name: "tak")
yagom.callStudent()
iOS를 처음 접할 때 모두들 UITableViewDelegate
를 통해서 Delegate 패턴을 접했을 것이다. Delegate
패턴은 단어 그대로 해당 타입의 특정 Method
구현을 다른 객체에게 위임 하는 것이다
protocol StudentDelegate: AnyObject {
func goSchool()
}
class Student {
weak var delegate: StudentDelegate?
func wakeUp() {
delegate?.goSchool()
}
}
class Parent: StudentDelegate {
func goSchool() {
print("아들을 깨워서 밥을 먹이고 학교에 데려다 준다")
}
}
let student = Student()
student.wakeUp()
//동작을 위임했지만 delegate가 없어서 출력 X
let parent = Parent()
student.delegate = parent
//delegate로 parent가 선임되어서 parent에서 정의한 goSchool이 실행됨
//아들을 깨워서 밥을 먹이고 학교에 데려다 준다
student.wakeUp()
참고)
https://jcsoohwancho.github.io/2019-11-30-KVO(Key-Value-Observing)/
KVO는 A객체에서 B객체의 프로퍼티가 변화됨을 감지할 수 있는 패턴이다. 메소드나 다른 액션에서 나타나는 것이 아니라 프로퍼티의 상태에 반응하는 형태다
장점
단점
덧붙여서 Swift 4 전까지는 NSObject의 메소드인 observeValue(forKeyPath:change:context:)
를 오버라이드하여 옵저버를 추가했으나 Swift4부터는 구독하고 싶은 프로퍼티에 observe()를 추가하여 클로저로 사용할 수 있게 하였다. 그러나 Swift 상에서는 didSet이나 willSet 같은 것으로 충분히 대체가 가능할 것 같아 굳이 써야하나 싶은 패턴인 것 같다.
import Foundation
class SomeClass: NSObject {
@objc dynamic var value: String = "real"
}
let someObject = SomeClass()
let observing = someObject.observe(\.value, options: [NSKeyValueObservingOptions.initial]) { (object, change) in
print("SomeClass object value changed to \(object.value)")
}
someObject.value = "test"
//SomeClass object value changed to real
//SomeClass object value changed to text