써니쿠키의 IOS 개발일기

[swift] KVO, Notification 본문

swift 공식문서

[swift] KVO, Notification

sunnyCookie 2022. 9. 2. 10:57

📝 개념정리

✅ 1. KVO (Key-Value Observing)

KVO 개념정리는 애플 문서 아카이브- Key-value observing / 공식문서 Using Key-Value Observing in Swift 두 공식문서를 해석/정리한 내용입니다

  • KVO 란 object의 프로퍼티가 변경될 때 다른 Object가 직접 알림을 받을 수 있게 하는 메커니즘이다.
  • MVC(Model-View-Controller)디자인 패턴을 쓴 어플에서 Object간의 통신 모드이다.
    (ex: Model object의 상태를 View, Controllet layer Object와 동기화하는데 사용)
  • 일반적으로 controller가 model관찰 / View가 controller (지향하지만 간혹 model) 관찰
  • ✔️ 참고: UIKit 프레임워크의 클래스는 일반적으로 KVO를 지원하지 않지만 어플의 custom View, custom objects에서 여전히 KVO를 쓸 수 있다.
  • KVO에서는 하나의 Object가 다른 Object의 모든 프로퍼티를 관찰할 수 있다.
  • Object는 프로퍼티의 현재 값과 이전 값이 무엇인지 알 수 있다.
  • to-many 관계(대다관계)의 관찰자는 변경된 타입뿐만 아니라 변경에 관련된 Object가 어떤건지도 알려준다.
  • notification(알림) 메커니즘으론 KVO가 NSNotification및 NSNotificationCenter클래스에서 제공하는 메커니즘과 유사하지만 중요한 차이점도 있다.
  • NSNotificationCenter에서는 관찰자로 등록되어 모든 Object에 notification을 broadcast하는 central Object 가 있지만 KVO에서는 notification은 속성 프로퍼티 값이 변경될 때 관찰중인 Object로 직접 이동(go directly)합니다.

1-1 KVO 구현

  • NSObjec클래스를 를 상속한 클래스에서만 KVO를 사용할 수 있음.
  • 관찰되는 클래스가 관찰 하려는 프로퍼티에 대해 준수하는 키-값 관찰 인지 확인해야 합니다.
    • KVO 준수를 위해서는 관찰되는 객체의 클래스도 KVC를 준수해야 하고 프로퍼티에 대한 자동 관찰자 notifications을 허용하거나 프로퍼티에 대한 수동 키-값 관찰을 구현해야 합니다.
  • 값이 변경될 수 있는 Object의 관찰자를 추가합니다. addObserver:forKeyPath:options:context:.를 호출하면 됩니다. 관찰자는 애플리케이션의 또 다른 객체일 뿐입니다.
  • 관찰자 Object에서 메서드를 구현합니다 observeValueForKeyPath:ofObject:change:context:. 이 메서드는 관찰된 Object의 프로퍼티 값이 변경될 때 호출됩니다.
  • options에는 old / new / initial / prior 가능
  • 예시는 여기서! = 공식문서 Using Key-Value Observing in Swift, 제드티스토리

 

✅ 2. Notification

공식문서에서 정의와 주요토픽 부분을 정리해보겠다..!

A container for information broadcast through a notification center to all registered observers.

해석하자면 등록된 모든 관찰자에게 notification center를 통해 broadcast되는 정보 컨테이너를 Notification이라한다.

즉 NotificationCenter를 통해 정보를 저장하기 위한 구조체다. 정보가 담겨있고 알림을 등록한 옵저버들에게만 옵저버들에게 전달되는 구조체다.

2-1. Notification 구성

init(name:object:userInfo:) 을 이용해 새로운 Notification을 이니셜라이징해준다.

    init(
    name: Notification.Name,
    object: Any? = nil,
    userInfo: [AnyHashable : Any]? = nil
)
  • name
    전달하고자 하는 notification의 이름 (이걸 통해 알림을 식별한다)
  • object
    전달하고자 하는 데이터(객체)(없으면 nil)
  • userInfo
    notification과 관련된 값(없으면nil)으로 extra data를 보내는 데 사용가능

2-2. Notification Center (NSNotificationCenter)

공식문서 정의
A notification dispatch mechanism that enables the broadcast of information to registered observers.

해석하자면 등록된 관찰자에게 정보를 브로드캐스트할 수 있는 notification 발송 메커니즘이다.

 

notification이 오면 (observer pattern을 통해서) 등록된 옵저버들에게 동시에 notification을 전달하는 클래스다. notification을 발송하면 NotificationCenter에서 메세지를 전달한 observer를 처리할 때까지 대기한다. 즉, 흐름이 동기적으로 흘러간다.

 

notification Center를 통해서 앱의 한 파트에서 다른 파트로 데이터를 전달할 수 있다. Notification이 오면 등록된 observer list를 스캔한다. Notification Center는 어플리케이션 어느 곳에서 어느 객체와도 상호작용을 할 수 있다.

 

✏️ 기본 Notification Center 얻기

  • default : 애플리케이션의 기본 노티피케이션 센터다

✏️ 옵저버 추가 및 제거

  • addObserver(_:selector:name:object:)
    옵저버 등록
  • removeObserver(_:name:object:)
    옵저버 제거 : 노티피케이션 센터의 메서드를 가리키는 장소에서 일치하는 이름을 제거한다
  • removeObserver(_:)
    옵저버 제거: 노티피케이션 센터의 메서드를 가리키는 장소에서 모든 이름을 제거한다

2-3.

1️⃣ NotificationCenter에 Observer 등록하기

  • NotificationCenter에 addObserver 과정을 선행해줘야 원하는 관찰이 가능하다
  • 옵저버 등록인 addObserver 반대 의미로 removeObserver(_:name:object:)도 있는데 방식은 같다.self 에서 "Sunny"라는 이름을 가진 notificaiton을 관찰할 것이고, 해당 notification이 발생하는 경우에 `talkTo`라는 함수를 호출해 실행할 것이다. 라는 뜻입니다.
NotificationCenter.default.addObserver(self, 
					selector: #selector(talkAbout(_:)), 
					name: Notification.Name("Sunny"), object: nil) 

@objc func talkAbout(_ notification: Notification) { 
	// 실행해 줄 코드 ~ 
}
  • self : notification의 관찰자(observer)가 될 object
  • selector : notification이 오면 실행할 함수
  • name : notification의 이름
  • object : 지정하면 특정 sender로부터만 notification을 받음 (optional)➕TIP ✏️ **Notification Name을 설정해줄 때 Notification.Name의 extension으로 따로 빼서 쓰면 더 유용하고 편하다.**
  • notification이 오면 실행해주는 함수는 `talkAbout()`은 target-action 패턴과 같은 형식으로 진행된다. 함수는 Notification 객체의 파라미터를 하나 갖게 된다.
extension Notification.Name {
    static let sunny = Notification.Name("sunny")
    static let ash = Notification.Name("ash")
    static let summerCat = Notification.Name("summerCat")
}

2️⃣ NotificationCenter로 Post하기 (발송하기)

✏️ 발송하기

  • post(_ :)
    지정된 노티피케이션을 노티피케이션 센터에 발송한다
  • post(name:object:userInfo:)
    지정된 이름, 보낸 객체, 보낼 정보로 노티피케이션을 만들어 노티피케이션 센터에 발송한다
  • post(name: object:)
    지정된 이름, 보낸 객체로 노티피케이션을 만들어 노티피케이션 센터에 발송한다
  • NotificationCenter.default.post(name: Notification.Name("sunny"), object: nil)
  • name : 전달하고자 하는 notification의 이름 (이걸 통해 알림을 식별)
  • object : addObserver의 objectd와 목적이 같은데, 특정 sender의 notification만 받고 싶은 경우에 작성해주면 됨 (filter같은기능) (없으면 nil)
  • userInfo : notification과 관련된 값, extra data를 보내는데 사용 가능 (없으면 nil)
    이때 userInfo의 타입은 위에서 말했다시피 [Anyhasable : Any] 이기 때문에 다운캐스팅해서 원하는 타입에 맞춰 작성해주면 된다.

참고자료:
애플 문서 아카이브- Key-value observing
공식문서 Using Key-Value Observing in Swift
제드 - Key-Value Observing(KVO) in Swift
애플공식문서 - Notification
애플공식문서 - NotificationCenter
후리스콜링개발 - [iOS] NotificationCenter?
Kane-young - [iOS/Swift] Notification Center, Delegate, KVO??


2. KVO와 노티피케이션의 장단점은?

 

 

장점

단점
KVO 1. Object간의 동기화가 쉬움

2. Object의 내부 코드변경없이 외부에서 Object 변화를 알 수 있음.

3. 변경전 값 oldValue와 변경후 값인newValue를 알 수 있음

4. key.path로 옵저빙하기 떄문에nested objects도 옵저빙 가능
1. 많은 value를 감지할 때 많은 조건문이 필요

2. NSObject를 상속받은 클래스에서만 사용이 가능.
Notifacation 1. 많은 줄의 코드가 필요없이쉽게 구현이 가능하다.

2. 다수의 Object들에게 동시에 이벤트의 발생을 알려줄 수 있다.
1. key 값으로 Notification의 이름과 userInfo를 서로 맞추기 때문에 컴파일시 구독이 잘 되고 있는지, 올바르게 userInfo의 value를 받아오는지 체크가 불가능 하다.

2. 추적이 쉽지 않을 수도 있다3. Notification post 이후 정보를 받을 수 없다.

👩🏻‍💻수업내용

✅ Observing [ KVO/ 노티피케이션 센터 / 프로퍼티감시자 ]

  • 프로퍼티감시자
    한계점은 코드의 주인이어야한다는 점이다. didSet, willSet 코드를 타입내부에서 구현해줘야하기 때문에 타입의 주인이 아니면 사용할 수 없다.
  • KVO
    KVO는 스위프트를 지원하는 코드가아니고 object-c를 지원하는 코드여서 코드가 object-c구현법과 비슷하다. 코드의 구현부를 변경하지않기 떄문에 코드의 주인일 필요는 없어 프로퍼티감시자의 한계를 보안할수있다. 조금의 한계는 NSObject를 상속받은 클래스에만 사용할 수 있다는 점인데 외부에서 UIKit는 대부분 NSObject를 상속받은 클래스들이기 때문에 다루는데 큰 문제는 없을 것이며 외부에서 observing 이 필요할 때 사용할 수 있다.
    (변하는 값이 내가 변했다고 값을 감시자에게 직접 알려주는 방식이다)
  • Notification Center
    나의 변화를 세상에 전역적으로 외치는 방식이다
    addObserver로 구독설정하고 post를 통해 세상에 외치는걸 듣는것이라 할 수있다. 인스턴스끼리 서로 몰라도 변화를 감지할 수 있어서 결합도를 낮출 수 있다는 장점이 있지만 반대로 생각하면 어떤 변화를 감지한건지 추적하기가 까다로운 문제도있다.
반응형
Comments