본문 바로가기

iOS

[iOS] NotificationCenter

Notification

등록된 노티피케이션에 노티피케이션 센터를 통해 정보를 전달하기 위한 구조체이다.

 

주요 프로퍼티

var name: Notification.name
// 알림을 식별하는 태그

var object: Any?
// sender가 옵저버에 보내고자 하는 객체. 주로 sender 객체를 전달하는 데 쓰임

var userInfo: [AnyHashable: Any]?
// 노티피케이션과 관련된 값 또는 객체의 저장소

특정 행동으로 인해 작업이 시작되거나 완료되는 시점에 다른 인스턴스로 노티피케이션 발생 시, 필요한 데이터를 같이 넘겨줄 수 있다.

ex. 네트워킹 시작 및 완료되는 시점. 음악 및 동영상 재생이 끝나는 시점

 

 

 

NotificationCenter

등록된 옵저버에게 동시에 노티피케이션을 전달하는 클래스. NotificationCenter 클래스는 노티피케이션을 발송하면 노티피케이션센터에서 메세지를 전달한 옵저버가 처리를 할 때까지 대기한다. 즉, 흐름이 동기적(synchronous)으로 흘러간다. 노티피케이션을 비동기적으로 사용하려면 NotificationQueue를 사용하면 된다.

 

 

기본 노티피케이션 센터 얻기

 class var `default`: NotificationCenter { get }
 // 애플리케이션의 기본 노티피케이션

 

 

옵저버 추가 및 제거

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

name : 옵저버 블록으로 보낼 노티피케이션의 이름

obj : 옵저버 블록으로 보내는 객체

(object에 특정 객체를 명시하면 명시한 객체가 발송한 노티피케이션일 때만 해당 이름의 노티피케이션을 수신한다.)

queue : 블록이 실행되는 operation queue

(nil일 경우, 블록은 전송 스레드에서 동기적으로 실행된다.)

block : 노티피케이션을 받았을 때 실행하는 블록 (클로저)

 

 

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

 

 

노티피케이션을 노티피케이션 센터의 메소드를 가리키는 장소에 이름을 추가한다. (????)

 

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

노티피케이션 센터의 메소드를 가리키는 장소에서 일치하는 이름을 제거한다.

 

 func removeObserver(_ observer: Any)

노티피케이션 센터의 메소드를 가리키는 장소에서 모든 이름을 제거한다.

 

 

노티피케이션 발송

 func post(_ notification: Notification)

지정된 노티피케이션을 노티피케이션 센터에 발송한다.

 

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

지정된 이름, 보내는 객체, 보낼 정보로 노티피케이션을 만들어 노티피케이션 센터에 발송한다.

 

func post(name aName: NSNotification.Name, object anObject: Any?)

지정된 이름, 보내는 객체로 노티피케이션을 만들어 노티피케이션 센터에 발송한다.

 


예제

일반 노티피케이션

 // 옵저버 등록
 NotificationCenter.default.addObserver(self, selector: #selector(didRecieveTestNotification(_:)), name: NSNotification.Name("TestNotification"), object: nil)

 @objc func didRecieveTestNotification(_ notification: Notification) {
         print("Test Notification")
 }
 
 
 // 발송
 NotificationCenter.default.post(name: NSNotification.Name("TestNotification"), object: nil, userInfo: nil)

 

 

User Info 정보를 담은 노티피케이션

// 옵저버 등록
NotificationCenter.default.addObserver(self, selector: #selector(didReceiveTestNotification(_:)), name: NSNotification.Name("TestNotification"), object: nil)

@objc func didReceiveTestNotification(_ notification: Notification) {
 		guard let testString: String = notification.userInfo?["TestString"] as? String else { return }
         print("testString :", testString)
 }
 
 
 
// 발송자
let userInfo: [AnyHashable: Any] = ["TestString":"Hi"]

NotificationCenter.default.post(name: NSNotification.Name("TestNotification"), object: nil, userInfo: userInfo)​

 


 

직접 노티피케이션을 생성, 전송, 수신  

let DidReceiveFriendsNotification: Notification.Name = Notification.Name("DidReceiveFriends")

func requestFriends() {
    guard let url: URL = URL(string: "https://randomuser.me/api/?results=20&inc=name,email,picture") else { return }
    let session: URLSession = URLSession(configuration: .default)
    
    //url로 요청, 요청에 대한 서버의 응답이 왔을 때 호출되는 클로저
    let dataTask: URLSessionDataTask = session.dataTask(with: url) { (data: Data?, response: URLResponse?, error: Error? )
        in
        if let error = error {
            print(error.localizedDescription)
            return
        }
        guard let data = data else { return }
        do {
            let apiResponse: APIResponse = try JSONDecoder().decode(APIResponse.self, from: data)
            NotificationCenter.default.post(name: DidReceiveFriendsNotification, object: nil, userInfo: ["friends":apiResponse.results])
            // result 값을 실어서 노티피케이션을 보냄
        } catch (let error) {
            print(error.localizedDescription)
        }
    }
    dataTask.resume()
}

 

NotificationCenter.default.addObserver(self, selector: #selector(self.didReceiveFriendsNotification(_:)), name: DidReceiveFriendsNotification, object: nil)

    @objc func didReceiveFriendsNotification(_ noti: Notification) {
        
        //아까 실어서 보냈던 userInfo
        guard let friends: [Friend] = noti.userInfo?["friends"] as? [Friend] else { return }
        self.friends = friends
        
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }

self: 내가 노티를 받을 거야~ 

어떤 메소드를 통해서? didReceiveFriends~ 통해서~

그러면 DidReceiveFriendsNotification 이라는 이름으로 가져온 거 내가 받아올게~!

이렇게 노티피케이션 센터에다가 나 이제 들을거야~ 라고 등록할게

노티 발생하면 didReceive~ 메소드를 통해서 알려줘 ~ 그럼 그 메소드를 호출할거양 ~ 

 

+

어떠한 스레드에서 노티피케이션을 발송하면, (= 발송 코드가 어떠한 스레드에 있다면) 받는 쪽의 코드도 해당 스레드에서 동작한다.

즉, 클로저가 있는 백그라운드 스레드에서 이를 호출해버리면 백그라운드 스레드에서 didReceive~ 를 호출하게 됨.

그래서 didReceive~ 메소드 안에서, 메인에서 작동할 필요가 있는 코드는 메인 스레드로 가져와줘야 한다. 

 

 

 

노티피케이션 센터는 잘 활용하면 아주아주 좋지만, 키 값도 따로 정리해 줘야 하고 코드도 분산되기 때문에 간단한 작업을 하기에는 적절하지 않을 수 있다. 전송, 수신, 등록 각자 다 해 주어야 하기 때문에!

 

 

 

 

 

 

 

[LECTURE] 2) 노티피케이션 센터의 활용 : edwith

강의 영상 - 부스트코스

www.edwith.org

 

'iOS' 카테고리의 다른 글

[iOS] iOS에서 체크박스 사용하기  (0) 2020.07.13
[iOS] JSON 파일 다루기  (0) 2020.06.15
[iOS] CMTime  (0) 2020.06.13
[iOS] AVFoundation, AVPlayer, AVPlayerLayer  (0) 2020.06.13
[iOS] AVKit, AVPlayerViewController  (0) 2020.06.13