Delegates와 Notification 방식의 차이점에 대해 설명하시오.

이하연·2021년 8월 15일
1

[OS] 운영체제

목록 보기
8/12

목표

  • Delegates와 Notification 방식의 차이점에 대해 설명하시오.
  • KVO(Key Value Observing) 동작 방식에 대해 설명하시오.

3가지 패턴이 나오게 된 배경

  • 어플리케이션의 특성상 객체 간의 소통은 필수적입니다. 하지만, 다른 객체에 종속되어 동작하는 것은 재사용성과 독립적 기능요소 측면에서 볼때는 바람직하지 않습니다. 그래서 하나의 객체가 다른 객체와 소통은 하지만 묶이기는 싫을 경우에 사용하기 위해서 등장했습니다.
  • 공통점 : 세 패턴 모두 특정 이벤트가 일어나면 원하는 객체에 알려주어 해당되는 처리를 하는 방식입니다.
  • 예시 : ViewController는 한 View를 관리하는 독립적인 객체로서 존재해야지, 소통을 위해 다른 ViewController에 묶여 동작하는 것은 옳지 않은 방식입니다. → 이때 Delegation, Notification, KVO를 사용합니다.

Delegation

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

서로 데이터를 보내주고 통신 할 수 있도록 하는 걸

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이후의 정보를 받을 수 없다는 단점이 있습니다.

동작원리

  1. 한 객체에서 이벤트가 발생했다는 것을 Notification Center로 송신합니다.
  2. Notification Center에서 발생된 이벤트를 등록된 모든 옵저버에 보내고
  3. 해당 이벤트를 구독하는 Observer가 있다면 해당 화면에서 이벤트에 대한 처리를 할 수 있습니다.
  4. 만약 등록된 옵저버가 많아지면 모든 옵저버리스트를 찾아가기에 성능이 저하될 수 있습니다.

Delegate, Notification 비교

각각 언제 사용한다고 생각하시나요?

Delegate는 한 화면에서 많은 이벤트와, 해당되는 객체의 데이터를 가져와야할 때 쓰면 적합하다고 생각해요. TableView의 Delegate함수를 보면 셀 갯수, 셀 설정, 셀 크기, 등 많은 이벤트를 위한 함수와, 이벤트가 발생했을 때 가져올 수 있는 데이터에 접근하기위한 변수들이 설정 되어있잖아요?? 그렇듯 한 속성에대한 다양한 이벤트를 처리하기 위해서는 Delegate가 적합하다고 생각해요

Notification은 한 이벤트에 대해 다수의 수신자가 있을 경우에 쓰면 좋을 것 같아요. UI의 업데이트를 위한 이벤트를 받을 때, 화면간 연결관계가 없을 때, 바로 다음 화면이 아닌 건너건너 depth가 깊은 화면에 이벤트를 줄 때 좋을 것 같아요.depth가 깊다면 Delegate를 채택하고 객체를 담을 변수를 전달하는 과정이 복잡하다고 생각해요.

KVO

KVO는 A객체에서 B객체의 키의 값이 변화됨을 감지할 수 있는 패턴입니다. 위의 두 패턴이 주로 Controller와 다른 객체 사이의 관계를 다룬다면, KVO 패턴은 객체와 객체 사이의 관계를 다룰 때 적합합니다.

메소드나 다른 액션에서 나타나는 것이 아니라, 프로퍼티의 상태에서 반응하는 형태

동작방식

모델 객체의 어떤 값이 변경되었을 경우 이를 UI에 반영하기 위해서 컨트롤러는 모델 객체에 Observing을 도입하여 델리게이트에 특정 메시지를 보내 처리할 수 있도록 하는 것

즉, 변수에 코드를 붙여 변수가 변경될 때마다 코드가 실행되도록 하는 방법을 의미한다. property observers(willset , didSet)과 아주 유사한데 KVO는 타입 정의 밖에서 observe를 추가한다는 점이 다르다. KVO는 순수 스위프트 코드로는 그리 좋지 않은데, 그 이유는 Objective-c 런타임에 의존 하고 있기 때문이다. 그래서 NSObject를 상속받기 위해 @objc 를 반드시 붙여줘야 한다. 특히 KVO는 속성 각각에 @objc dynamic 을 붙여줘야 한다.

3가지 패턴의 장단점

0개의 댓글