Notification Center로 이벤트 전달하기

고라니·2023년 10월 10일
0

TIL

목록 보기
39/67

NotificationCenter와 Notification은 앱 내의 다양한 컴포넌트 간 통신을 가능하게 해주는 유용한 도구라고 한다. 전에 알아보았던 KVO와 비슷하면서 다른것 같은데 한번 알아보도록 하자.

Notification?

Notification Center를 통해 등록된 관찰자에 정보를 발송하는 컨테이너 객체로 즉, 방송되는 노티피케이션의 내용을 포장하는 역할이라고 생각하면 된다.

주요 프로퍼티 세 가지

  • name: 노티피케이션의 유형을 식별하기 위해 사용
  • object: 노티피케이션을 발행한 객체를 참조하기 위해 사용
  • userInfo: 노티피케이션과 관련된 추가적인 정보나 객체를 딕셔너리 형태로 전달하기 위해 사용

extention으로 Notification.Name 정의하기(option)

노티피케이션 유형을 식별하기 위한 name을 관찰자를 등록할때 and Notification을 발송 할 때 직접 정의하는것도 가능하지만 extention에 미리 등록하는것이 안전하고 편리하다.

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

Notification Center?

Notification Center는 Observer 패턴의 구현체로, 특정 이벤트나 정보를 방송하고 그것을 수신한다. 이를 통해 앱의 다양한 부분이 서로 독립적으로 작동하면서도 필요한 정보나 이벤트 공유가 가능하다.

  • Notification Center는 등록된 Observer(관찰자)에게 정보를 발송하기 위한 정보 전달 메커니즘이다.
  • 객체들은 특정 알림을 수신하기 위해 노티피케이션 센터에 Observer(관찰자)로 등록할 수 있다.
  • 하나의 객체는 여러 종류의 알림을 수신하기 위해 여러번 등록 가능하다.
  • 실행중인 앱은 하나의 기본 Notification Center가 있다. 앱 전체 공유(싱글톤), 필요에 따라 추가적인 Notification Center를 생성하여 특정 컨텍스트 내에서 통신 조작 가능하다.

Observer 추가, 제거

1. addObserver(forName:object:queue:using:)

func addObserver(
    forName name: NSNotification.Name?,
    object obj: Any?,
    queue: OperationQueue?,
    using block: @escaping @Sendable (Notification) -> Void
) -> NSObjectProtocol

: NotificationCenter에 새로운 관찰자 등록, 주어진 블록으로 Notification을 수신

  • forName: 관찰하려는 Notification 식별 이름. nil 사용하면 모든 Notification 수신
  • object: 특정 객체로부터의 노티피케이션 관찰하기 위해 객체 지정. nil 사용하면 모든 객체로부터 노티피케이션 수신
  • queue: Notification을 처리할 연산 큐. nil의 경우 현재 스레드에서 Notification 처리
  • using: Notification을 수신할 때 실행될 블록
  • 반환: Observer를 낮우에 제거할 때 사용하기 위한 토큰

addObserver(forName:object:queue:using:) 메서드를 사용하여 관찰자를 등록하면, 이 메서드는 NSObjectProtocol 타입의 값을 반환한다. 이 반환된 값은 "토큰"으로 간주되며, 나중에 해당 관찰자를 NotificationCenter에서 제거할 때 사용 가능하다.

2. addObserver(_:selector:name:object:)

func addObserver(
    _ observer: Any,
    selector aSelector: Selector,
    name aName: NSNotification.Name?,
    object anObject: Any?
)

: NotificationCenter에 새로운 괄찰자 등록. Notification을 수신할 때 주어진 선택자

  • observer: Obsever객체
  • selector: Notification 수신 시 호출될 메서드
  • name: 관찰하려는 Notification 식별 이름 (동일)
  • object: 특정 객체로부터의 Notification 관찰하기 위해 객체 지정(동일)

3. removeObserver(_:name:object:)

func removeObserver(
    _ observer: Any,
    name aName: NSNotification.Name?,
    object anObject: Any?
)

: NotificationCenter의 매개변수 조건과 일치하는 관찰자 항목을 제거한다.

  • observer: 제거할 Observer객체
  • name: 제거할 Notification 식별 이름
  • object: 특정 객체로부터의 노티피케이션만 제거하려면 해당 객체 지정

4. removeObserver(_:)

func removeObserver(_ observer: Any)

: NotificationCenter의 발송 테이블에서 지정된 모든 관찰자항목 제거

  • observer: 제거할 Observer (addObserver(forName:object:queue:using:)의 반환 값으로 제거하는것도 가능 )

Notification 발송(Post)

1. post(Notification)

func post(_ notification: Notification)

: 주어진 노티피케이션을 NotificationCenter에 발송, 이미 생성된 Notification객체를 직접 전달

  • Notification: 발송할 노티피케이션 객체.

2. post(name:object:userInfo:)

func post(
    name aName: NSNotification.Name,
    object anObject: Any?,
    userInfo aUserInfo: [AnyHashable : Any]? = nil
)

: 주어진 이름, 발송자, 추가 정보로 Notification을 생성한 후 전달, 이 메서드는 Notification 생성과 NotificationCenter 발송을 한번에 처리, UserInfo를 사용하여 관련된 데이터 추가 전달 가능.

  • name: Notification 식별 이름
  • object: Notificaiong 발송자
  • userInfo: 함께 전달할 추가 정보(Dictionary)

3. post(name:object:)

: 주어진 이름과 발송자로 Notification 생성 후 발송, post(name:object:userInfo:)와 유사하지만 추가정보 없이 생성하고 전달

  • name: Notification 식별 이름
  • object: Notification 발송자

작동 과정

  1. 관찰자 등록: 객체는 특정 Notification을 수신하기 위해 NotificationCenter에 Observer로 등록한다.
  2. Notification 발행: 특정 이벤트 발생 시 관련 정보와 함께 노티피케이션을 NotificationCenter에 발송
  3. 노티피케이션 수신: 등록된 Observer는 해당 Notification을 수신하고, 지정된 행동을 실행(콜백함수)

예시 코드

Notification 이름 정의

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

Notification Observer 등록 및 처리

class ObserverClass {
    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleNotification(_:)), name: .myNotification, object: nil)
    }
    
    @objc func handleNotification(_ notification: Notification) {
        print("노티피케이션 발송!")
        
        if let data = notification.userInfo as? [String: String] {
            for (key, value) in data {
                print("\(key) : \(value)")
            }
        }
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self, name: .myNotification, object: nil)
    }
}

노티피케이션 발송

class PostingClass {
    func sendNotification() {
        NotificationCenter.default.post(name: .myNotification, object: nil, userInfo: ["Key": "Value"])
    }
}

실행

let observer = ObserverClass()
let poster = PostingClass()

poster.sendNotification()
// 출력:
// 노티피케이션 발송!
// Key : Value

KVO와 Notification

이 둘은 객체 간의 통신을 위해 사용된다는 공통점이 있다. 이 둘은 상황에 따라 적절하게 선택해야 하며, 가끔은 함께 사용되기도 한다.

NotificationCenter와 Notification

: 객체 간 느슨한 결합으로 이벤트를 전달하는 기능을 제공한다. 객체를 관찰자로 등록하면 해당 이벤트가 발생했을 때 등록된 관찰자 객체에 알림을 전달한다.

둘 다 객체 간의 통신을 위해 사용되지만, 상황과 방식에 차이가 있다.

KVO

  • 용도: 객체의 특정 속성의 변경을 관찰하기 위한 메커니즘. 객체의 속성이 변경될 때 알림 받음
  • 결합도: 감시하려는 객체와 그 객체의 특정 속성에 직접적으로 종속
  • 적용 범위: 특정 객체의 특정 속성에 한 함

NotificationCenter

  • 용도: 특정 이벤트가 발생했을 때 등록된 관찰자에게 Notification 전달
  • 결합도: 이벤트 발생과 수신 사이에 느슨한 결합, 여러 객체가 동일한 이벤트 관찰 가능
  • 적용 범위: 앱 전체에 광범위 하게 사용

마치면서

NotificationCenter는 서로 다른 로직을 담당하는 객체들 사이에서 낮은 결합도로 정보나 이벤트를 효과적으로 전달할 수 있는 유용한 도구인듯 하다. 하지만 오히려 코드가 복잡해질 수 있고 흐름을 파악하기 어려워 질 수 도 있기 때문에 무분별하게 사용하지 않는것이 정말 중요하다고 느껴진다. 또한 KVO의 주의점과 마찬가지로 잘못 사용하면 예기치 못한 오류나 메모리 누수를 초래할 수 있다고 하니 주의하도록 하자.

profile
🍎 무럭무럭

0개의 댓글