Apple-CS-interview / iOS-CS-interview

7 stars 0 forks source link

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

Open Do-hyun-Kim opened 1 year ago

Do-hyun-Kim commented 1 year ago

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

NotificationCenter 이란?

Nofication 이란?

name : 전달하고자 하는 Nofication의 이름(식별자)

object : 발신자 observer에게 보내려는 객체

userInfo: Notification과 관련된 값 또는 객체의 저장소 Extra data를 보내는데 사용 가능

public struct Notification : ReferenceConvertible, Equatable, Hashable {
   /// A tag identifying the notification.
    public var name: Notification.Name

    /// An object that the poster wishes to send to observers.
    ///
    /// Typically this is the object that posted the notification.
    public var object: Any?

    /// Storage for values or objects related to this notification.
    public var userInfo: [AnyHashable : Any]?
}

NotificationCenter 예시 코드

extension Notification.Name {
    static let didDeliveName = Notification.Name("didDeliveName")
    static let didDeliveAge = Notification.Name("didDeliveAge")
}

class Jenny {

    func didDeliveName() {
        NotificationCenter.default.post(name: NSNotification.Name.didDeliveName, object: "jenny")
    }

    func didDeliveAge() {
        NotificationCenter.default.post(name: NSNotification.Name.didDeliveAge, object: 26)
    }

}

class Company {

    var employeeName: String?
    var employeeAge: Int?

    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(didReceiveName(_:)), name: .didDeliveName, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(didReceiveAge(_:)), name: .didDeliveAge, object: nil)
    }

    @objc
    private func didReceiveName(_ notification: Notification) {

        /// 해당 notification 에서는 jenny object 만 넘겨짐 -> didReceiveName 식별자에게 전달되는 데이터는 "jenny" 이기 떄문
        print("object Data: \(notification.object)")

        guard let employeeName = notification.object as? String else { return }
        self.employeeName = employeeName
    }

    @objc
    private func didReceiveAge(_ notification: Notification) {
        /// 해당 notification 에서는 26 object 만 넘겨짐 -> didReceiveAge 식별자에게 전달되는 데이터는 26 이기 떄문
        print("object age data: \(notification.object)")
        guard let employeeAge = notification.object as? Int else { return }
        self.employeeAge = employeeAge
    }

}

let jenny: Jenny = Jenny()

let myCompany: Company = Company()

jenny.didDeliveName()
jenny.didDeliveAge()
print(myCompany.employeeName)
print(myCompany.employeeAge)

NotificationCenter 장점

NotificationCenter 단점

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

Delegate는 Protocol 기반으로 정의 하여 사용되기때문에 이벤트를 대신 처리할 객체가 채택하여 사용하게 됩니다. 이처럼 1:1 로 커뮤니케이션 할때 유용하게 사용 할 수 있으며 1:N 으로 커뮤니케이션을 하게 된다면 불필요한 메소드를 구현하게 되어 불필요한 메서드를 구현 하게 될 수 있습니다. 이 뿐만 아닌 Delegate는 Protocol 기반으로 구현되기 때문에 Notification 보다 많은 코드량을 요구 하게 되며 이벤트를 알리고 싶은 경우 NotificationCenter 보다 비효율적인 부분이 있습니다

Notification 같은 경우에는 NotificationCenter 객체를 사용하여 여러 Notification 이 오면 Observer Pattern 을 통해 등록된 Observer 들에게 Notification 을 전달 할 수 있기 때문에 1:N 커뮤니케이션에 유용합니다. 하지만 제 3자 객체 (NotificationCenter) 객체가 필수적으로 필요하며 key값으로 Notification.Name 이 필요하기 때문에 컴파일 시에 구독이 잘 되고 있는지에 대해 확인이 어렵다는 것이 단점이며, SingleTone Pattern을 사용하고 있기 때문에 deinit 시에 removeObserver 를 해줘야 합니다.

📝 참고 사이트

ronick-grammer commented 1 year ago

Notification 이란

이벤트 발생여부를 옵저버를 등록한 객체들에게 알려주는 방법이다.

// 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 ObserverViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // 옵저버를 추가해 구독이 가능하게끔 함
        NotificationCenter.default.addObserver(self, selector: #selector(notificationReceived(notification:)), name: Notification.Name("notification"), object: nil)
    }

    // iOS 9 이상이 아닐 경우에는 removeObserver를 해줘야 함
    deinit {
        NotificationCenter.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)
    }
}

Delegate와 Notification의 차이점

delegate

Notification

무엇을 사용하는 것이 좋을까

다수의 객체에게 이벤트를 알려야 한다면 Notification을 사용하는 것이 좋을 수 있다. delegate 패턴을 사용하게 되면 로직의 흐름을 따라가기 수월하다는 장점이 있지만, 다수의 객체가 이벤트를 받아야 하기 때문에 그 이벤트를 받는 객체의 수만큼 delegate를 생성하고 뷰들의 depth에 따라 넘겨주고 이벤트 위임 처리를 해야하는 어려움이 있다. Notification을 사용하면 광역적으로(전역적으로) 그러할 필요없이 처리해줄 수 있다.

📝 참고 사이트

Hminchae commented 1 year ago

Delegate

Delegate 사용 장점

Delegate 단점

Notification

Notification 사용 장점

Notification 사용 단점

📝 참조

vichye-1 commented 1 year ago

공통점

Delegation

특징

장점

단점

Notification

특징

장점

단점

어디에 써야할까?

정리

DelegationNotification의 가장 큰 차이점은 수신자가 발신자의 정보를 알고 있는지의 여부이다.

Delegation 방식에서는 수신자가 발신자의 정보를 알고 있어야 한다.

하지만 Notification은 단순히 어떤 값의 변화를 포착하여 그에 맞는 이벤트를 발생시켜주면 된다.

Delegate를 사용하여 설계하지 않고 Notification만 가지고 설계를 했다면 다른 사람이 코드를 유지보수할 때 이 Notification을 누가 Subscribe 하고 있는지 알기가 어렵다.

반면 Delegate로 설계를 했다면 해당 Delegate의 이름, 프로토콜의 메서드 등을 통해 어떤 과정에 의해 이벤트 처리 로직이 작동하는지 파악하기 한결 수월하다.

하지만 여러 오브젝트들의 동시에 어떤 이벤트를 받고, 이를 모두 반영해야하는 경우, Notification이 적절할 수 있다. 이에 대한 예로는 로그인 상태가 변하여 많은 뷰들을 업데이트해야 하는 경우가 있다.

📝 참고