본문 바로가기
iOS/Swift

Swift) Notification, NotificationCenter

by Jiseong 2022. 2. 12.

Notification

NotificationCenter를 통해 정보를 저장하기 위한 컨테이너이다.

Notificationpost(전달)할 때 동기적으로 동작한다.

NotificationCenter

NotificationCenter에 등록된 observer에게 동시에 notification을 전달하는 클래스이다.

 

NotificationCenter 클래스는 한 객체가 이벤트가 발생했다는 Notification을 전달(post)하면, NotificationCenter에서 등록된 옵저버에게 객체에서 발생한 이벤트를 보낸다.

 

해당 이벤트를 다루는 옵저버가 있다면, 미리 설정해놓은 처리로(이런 이벤트가 들어오면, 이렇게 처리해라) 이벤트에 대한 처리(콜백, 피드백)을 한다.

 

.default = 앱 전체에 전역적으로 방송하는 방송국 

observer 등록 (addObserver)

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

addObserver의 프로퍼티이다.

  • name : 알림을 식별하는 태그 - 옵저버가 기다리는 이벤트의 이름이라고 생각하면 된다.

[name 등록 방법]

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

하나 더 있는데 이게 더 깔끔해서 이렇게 했다.

  • selector : name의 이름을 가진 이벤트가 발생하면 실행시킬 함수
  • object : 특정 객체가 보내는 이벤트만 받을게 라고 생각하면된다.  nil을 적어주면 특정 객체를 가리지않고, 누가 보내든 내가 기다리는 이벤트면 다 받을게 라는 뜻이다.
notificationCenter.addObserver(self, selector: #selector(changeDarkMode), name: .darkMode, object: nil)

등록된 이벤트를 받으면, 해당 이벤트에 대한 행동을 취하는 것이다.

이벤트 송신 (post)

@IBAction func darkModeBtn(_ sender: Any) {
     notificationCenter.post(name: .darkMode, object: nil)
} 

이벤트를 송신하는 부분이다. 발송자라고 보면된다.

  • name : 위에서와 같이, 송신할 이벤트의 이름
  • object : notification을 보낼 객체(객체 이름/익명이냐 특정 객체냐)

위 코드는 darkMode라는 버튼을 누르면 .darkMode라는 이름을 가진 이벤트가 notificationCenter에 대기중인 옵저버에게 수신된다.

 

확실히 말하면 notificationCenter에 수신되고, 거기서 해당 이벤트를 기다리는 옵저버에게 보내지는 것이다.

이벤트 수신시 실행될 함수 (selector)

@objc func changeDarkMode() {
        view.backgroundColor = .black
        mainLabel.textColor = .white
    }

.darkMode라는 이벤트를 받으면 selector에 명시되어있는 함수인 changeDarkMode() 를 실행해주는 식으로 만들어봤다.

전체 코드

//
//  ViewController.swift
//  NotificationExample
//
//  Created by 임지성 on 2021/10/23.
//

import UIKit

let notificationCenter : NotificationCenter = .default // .default = 앱 전체에 전역적으로 방송하는 방송국 

struct Test {

}
let test = Test()


class ViewController: UIViewController {

    @IBOutlet weak var mainLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        notificationCenter.addObserver(self, selector: #selector(changeDarkMode), name: .darkMode, object: self)
    }
    
    @IBAction func darkModeBtn(_ sender: Any) {
        notificationCenter.post(name: .darkMode, object: nil)
    }
    
    @objc func changeDarkMode() {
        view.backgroundColor = .black
        mainLabel.textColor = .white
    }
}

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

Test라는 구조체는 addObserver 메소드의 파라미터인 object를 테스트하려고 만들어봤다.

object를 다시 nil로 바꾸니 이벤트는 정상적으로 받아 함수를 실행하는 것을 확인했다.

반면 object에 test를 넣어주니 버튼을 눌러도 아무 반응이 없는 것을 확인했다. 

Test 구조체에 아무것도 없긴 하지만, object 파라미터를 이용해 발송자를 거를 수 있다는 것을 확실히 알게되어 만족스럽다.

 

근데 self를 넣어줘도 정상 동작할 줄 알았는데 안한다.

같은 클래스 내에서 발송자가 있는데.. 왜 안되는지 의문이다.

해결

post(이벤트 송신)의 object를 nil로 설정해놨기때문에 안되는 것이었다.

object를 nil로 설정한 것은 발신자표시제한을 한 것과 같기때문에, 아무리 옵저버가 "특정 객체에게서 오는 이벤트만 받을게" 하고 object: 특정 객체를 해도, 발송인이 익명처리가 되어있으니 알아볼 수가 없는 것이었다.

post에 object에 발송인을 self로 명시하고, 옵저버의 object에 self를 명시하니 정상적으로 동작하였다.

실행

조잡하지만 원하는대로는 된다.

Notification 장단점

장점

  1. 의존성을 줄여준다. 직접 접근하여 메소드를 호출하는 것이 아닌 NotificationCenter를 통해 접근하는 것이기 때문
  2. 여러개의 인스턴스에게 동시에 이벤트를 전달할 수 있다.
  3. 많은 코드가 필요하지 않아, 쉽게 구현 가능

단점

  1. 코드가 분산이 되기때문에(post, observer가 흩어져있다.) 추적이 쉽지 않을 수 있다.
  2. Notificaiton post 이후 정보를 받을 수 없음.

'iOS > Swift' 카테고리의 다른 글

왜 디자인 패턴을 중요시 여기는가?  (0) 2022.02.12
Swift) Struct vs Class  (0) 2022.02.12
Swift) Singleton  (0) 2022.02.12
Swift) KVO(Key-Value-Observing)  (0) 2022.02.12
일반화, 추상화, 캡슐화, 은닉화, 암호화  (0) 2022.02.12

댓글