본문 바로가기
IOS

Observer 패턴 vs Publisher/Subscriber 패턴 (1)

by eigen96 2023. 11. 7.
728x90

데이터 흐름: 입력과 출력

MVC 구조 내에는 두 가지 주요 데이터 흐름이 있습니다:

  1. 입력 흐름: 뷰에서 시작하여 사용자 입력을 컨트롤러에 전달하고, 컨트롤러는 이를 처리하여 모델의 데이터를 변경할 수 있습니다.
  2. 출력 흐름: 모델에서의 변경 사항에서 시작하여, 이러한 변경 사항이 UI에 빠르게 반영되어야 합니다. 여기서 Observer 패턴과 Publisher/Subscriber 패턴이 중요한 역할을 합니다.

 

 

 

NotificationCenter의 MVC 내 역할

 

NotificationCenter는 전통적인 Observer 패턴보다는 Publisher/Subscriber 패턴에 더 가깝습니다.

그 이유는 ...

NotificationCenter는 앱의 다른 컴포넌트 사이에서 느슨하게 결합된 통신 경로를 제공하는 중개자 역할을 하기 때문입니다.

모델 내의 데이터가 변경될 때, NotificationCenter는 이러한 변경 사항을 모든 관심 있는 파티(변경 사항을 구독하는 뷰와 컨트롤러)에게 알립니다.

 

  • 모델 업데이트: 모델이 변경되면(사용자 입력이나 다른 프로세스에 의해) NotificationCenter에 알림을 발행합니다.
  • NotificationCenter 알림: 이 알림은 등록된 모든 구독자에게 전송되며, 이는 일반적으로 뷰와 컨트롤러입니다.
  • 뷰와 컨트롤러 반응: 알림을 받은 뷰는 UI를 업데이트하고, 컨트롤러는 추가 데이터 처리를 시작할 수 있습니다.

옵저버 패턴: 모델과 옵저버의 능동적인 데이터 흐름 관리

컨트롤러가 모델에게 끊임없이 변화를 묻는 방식이 아닌,

모델 스스로가 변화를 감지하고 이를 옵저버에게 알려주는 방식을 '옵저버 패턴'이라고 합니다.

이 패턴은 특히 출력과 관련된 데이터 흐름을 처리할 때 유용하게 사용됩니다.

 

옵저버 패턴(Observer Pattern) 이해하기

옵저버 패턴의 핵심은 "변화를 관찰하고자 하는 객체(observer)"와 "변화를 알려주는 객체(observable)"의 관계입니다. 옵저버는 자신을 구독자로 등록함으로써, observable 객체의 상태 변화를 실시간으로 알 수 있습니다.

 

이 패턴은 주로 클래스(class)에 적용되며, 특히 클래스의 속성이 외부에서 변경되었는지 알고 싶을 때 사용합니다. Struct와 같은 값 타입보다는 참조 타입인 클래스에서 더 자주 사용됩니다.

 

 

예를 들어, 어떤 "Other" 객체가 변화를 일으키고 "Observer" 객체가 이를 감지하여 반응하는 상황에서, Observer는 Other 객체의 상태 변화를 바로 알 수 있습니다. 이렇게 등록과 동시에, 상태 변화가 있을 때 즉시 알림을 받는 방식이 옵저버 패턴의 전형적인 형태입니다.

 

 

Objective-C의 KVO(Key-Value Observing) 방식

전통적인 옵저버 패턴의 구현 방식 중 하나는 Objective-C의 KVO 방식입니다.

NSObject에 정의된 NSKeyValueObserving 프로토콜을 활용하여, Objective-C 속성의 변화를 감지합니다.

이를 위해 @objc 키워드를 사용하여 Objective-C 런타임에 의해 관리되는 속성들이 변화할 때 이를 감지할 수 있습니다.

 

 

Swift에서 KVO를 사용하기 위해서는 Objective-C 런타임과의 상호작용이 필요합니다.

이를 위해, 관찰하고자 하는 속성에 @objc 키워드를 붙여 Objective-C에서 접근 가능하도록 해야 합니다.

또한, 속성이 동적으로 변경되는 것을 감지하기 위해 dynamic 키워드도 추가해야 합니다.

 

KVO를 사용하기 위해서는 addObserver 메소드를 통해 해당 클래스의 인스턴스를 옵저버로 등록해야 합니다. 이때 forKeyPath 인자를 사용하여 어떤 속성을 관찰할 것인지 지정합니다.

 

self.addObserver(self, forKeyPath: "속성명", options: [.new, .old], context: nil)

 

 

옵저버가 등록되고 나면, 지정된 속성의 값이 변할 때마다 인스턴스의 observeValue(forKeyPath:of:change:context:) 메소드가 호출됩니다. 이 메소드는 관찰하고 있는 속성의 변경사항을 감지하여 적절한 작업을 수행하도록 오버라이드해야 합니다.

 

최근 Swift에서는 NSKeyValueObserving 프로토콜을 통해 KVO를 더욱 쉽게 사용할 수 있게 되었습니다.

이 프로토콜을 사용하면, observeValue 메소드를 구현하는 대신 클로저를 사용하여 관찰하고자 하는 속성에 대한 변화를 처리할 수 있습니다.

\.name은 객체의 name 속성에 대한 keyPath를 표현합니다.

observation = self.observe(\\.name, options: [.new]) { object, change in
    // 속성 'name'이 변경될 때 실행할 코드
}

 

 

KVO는 Objective-C 런타임에 의존한다는 점에서 거부감이 들 수 있을 것 같습니다.

순수 Swift 환경에서는 사용제약이 있을 수 있겠습니다.

다음엔 Publisher/Subscriber 패턴과 NotificationCenter에 대해 더 자세히 알아보겠습니다.

 

728x90

댓글