delegate는 지정된 객체가 해야하는 메소드들의 원형을 프로토콜 형태로 정해놓은 디자인 패턴입니다.
이때 delegate 역할을 하려는 객체는 이 protocol을 따르며 원형만 있던 메소드들의 구현을 합니다.
코드 예시
// 1) Delegate 프로토콜 선언
protocol SomeDelegate {
func someFunction(someProperty: Int)
}
class SomeView: UIView {
// 2) 순환 참조를 막기 위해 weak으로 delegate 프로퍼티를 가지고 있음
weak var delegate: SomeDelegate?
func someTapped(num: Int) {
// 3) 이벤트가 일어날 시 delegate가 동작하게끔 함
delegate?.someFunction(someProperty: num)
}
}
// 4) Delegate 프로토콜을 따르도록 함
class SomeController: SomeDelegate {
var view: SomeView?
init() {
view = SomeView()
// 6) delegate를 자신으로 설정
view?.delegate = self
someFunction(someProperty: 0)
}
// 5) Delegate 프로토콜에 적힌 메소드 구현
func someFunction(someProperty: Int) {
print(someProperty)
}
}
let someController = SomeController()
// prints 0
delegate는 커뮤니케이션 과정을 유지하고 모니터링하는 제 3의 객체가 필요가 없어 좋지만 많은 줄의 코드가 필요하며, 많은 객체들에게 이벤트를 알려주는 것이 어렵고 비효율적입니다.
서로 데이터를 보내주고 통신 할 수 있도록 하는 걸
Notification Center라는 싱글턴 객체를 통해 이벤트들의 발생 여부를 옵저버를 등록한 객체들에게 Notification을 post하는 방식으로 사용합니다. 이때 Notification name이라는 key 값을 통해 주고받을 수 있습니다.
// 1) Notification을 보내는 ViewController
class PostViewController: UIViewController {
@IBOutlet var sendNotificationButton: UIButton!
@IBAction func sendNotificationTapped(_ sender: UIButton) {
guard let backgroundColor = view.backgroundColor else { return }
// Notification에 object와 dictionary 형태의 userInfo를 같이 실어서 보낸다.
NotificationCenter.default.post(name: Notification.Name("notification"), object: sendNotificationButton, userInfo: ["backgroundColor": backgroundColor])
}
}
// 2) Notification을 받는 ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 옵저버를 추가해 구독이 가능하게끔 함
NotificationCenter.default.addObserver(self, selector: #selector(notificationReceived(notification:)), name: Notification.Name("notification"), object: nil)
}
// iOS 9 이상이 아닐 경우에는 removeObserver를 해줘야 함
deinit {
NotificationCetner.default.removeObserver(self)
}
@objc func notificationReceived(notification: Notification) {
// Notification에 담겨진 object와 userInfo를 얻어 처리 가능
guard let notificationObject = notification.object as? UIButton else { return }
print(notificationObject.titleLabel?.text ?? "Text is Empty")
guard let notificationUserInfo = notification.userInfo as? [String: UIColor],
let postViewBackgroundColor = notificationUserInfo["backgroundColor"] else { return }
print(postViewBackgroundColor)
}
}
notification은 많은 줄의 코드가 필요없이 쉽게 구현이 가능하며, 다수의 객체들에게 동시에 이벤트의 발생을 알려줄 수 있습니다. 하지만 notification post이후의 정보를 받을 수 없다는 단점이 있습니다.
Delegate는 한 화면에서 많은 이벤트와, 해당되는 객체의 데이터를 가져와야할 때 쓰면 적합하다고 생각해요. TableView의 Delegate함수를 보면 셀 갯수, 셀 설정, 셀 크기, 등 많은 이벤트를 위한 함수와, 이벤트가 발생했을 때 가져올 수 있는 데이터에 접근하기위한 변수들이 설정 되어있잖아요?? 그렇듯 한 속성에대한 다양한 이벤트를 처리하기 위해서는 Delegate가 적합하다고 생각해요
Notification은 한 이벤트에 대해 다수의 수신자가 있을 경우에 쓰면 좋을 것 같아요. UI의 업데이트를 위한 이벤트를 받을 때, 화면간 연결관계가 없을 때, 바로 다음 화면이 아닌 건너건너 depth가 깊은 화면에 이벤트를 줄 때 좋을 것 같아요.depth가 깊다면 Delegate를 채택하고 객체를 담을 변수를 전달하는 과정이 복잡하다고 생각해요.
KVO는 A객체에서 B객체의 키의 값이 변화됨을 감지할 수 있는 패턴입니다. 위의 두 패턴이 주로 Controller와 다른 객체 사이의 관계를 다룬다면, KVO 패턴은 객체와 객체 사이의 관계를 다룰 때 적합합니다.
메소드나 다른 액션에서 나타나는 것이 아니라, 프로퍼티의 상태에서 반응하는 형태
모델 객체의 어떤 값이 변경되었을 경우 이를 UI에 반영하기 위해서 컨트롤러는 모델 객체에 Observing을 도입하여 델리게이트에 특정 메시지를 보내 처리할 수 있도록 하는 것
즉, 변수에 코드를 붙여 변수가 변경될 때마다 코드가 실행되도록 하는 방법을 의미한다. property observers(willset , didSet)과 아주 유사한데 KVO는 타입 정의 밖에서 observe를 추가한다는 점이 다르다. KVO는 순수 스위프트 코드로는 그리 좋지 않은데, 그 이유는 Objective-c 런타임에 의존 하고 있기 때문이다. 그래서 NSObject를 상속받기 위해 @objc 를 반드시 붙여줘야 한다. 특히 KVO는 속성 각각에 @objc dynamic 을 붙여줘야 한다.