[iOS] Notification Center 구현하기

·

4 min read

[iOS] Notification Center 구현하기

😁 노티피케이션 센터란?

노티피케이션 센터란, 등록된 관찰자에게 알려줄 수 있도록 하는 알림 메커니즘이다. KVO 나 delegate 가 1 대 1 통신을 하는 것에 가깝다면 노티피케이션 센터는 여러곳에서 온 정보를 한 곳에서 모아서 다시 여러 곳으로 뿌려주는 것에 가깝다. 그래서 많은 사람들이 방송국에 노티피케이션 센터를 비유한다.

💻 노티피케이션 센터 구현해보기

NotificationCenter 공식 문서 노티피케이션 센터라는 이미 만들어져 있는 클래스를 사용하면 된다. 노티피케이션 센터는 싱글톤으로 구현되어 있기 때문에 어디에서 불러와도 같은 객체를 불러오게 된다.

이 순서를 따라서 구현하면 된다.
✅ 노티피게이션 센터에서 값을 전달하기 (post) ✅ Observer 등록하기 ✅ Observer가 실행할 함수 만들기 ✅ Observer 제거하기

🎥 유투버가 새로운 동영상을 올리면, 유투브에서 사용자에게 알람을 보내주는 코드를 만들어 보자.

🔔 노티피게이션 센터에서 값을 전달하기

알림을 보내줄 곳 만들기 post 메서드 공식문서

struct Video {
    let youtuber: String
    let title: String
}

class Youtube {
    func alram(video: Video) {
        NotificationCenter.default.post(name: Notification.Name("videoArlam"), object: nil, userInfo: ["mykey": video])
    }
}

비디오 객체를 파라미터로 넣어 alram 이란 메서드를 호출하면 비디오가 올라왔다는 것을 사람들에게 알려줄 코드이다. NotificationCenter.default.post 를 설정하는 것이 여기서 이제 알림을 줄 것이다. 라는 의미이다. 3가지 파라미터를 입력해주어야 한다. name object userInfo

name 노티피케이션 센터의 이름을 말한다. 만약 노티피케이션 센터를 여러개 만들 때에 어느 센터에서 값을 받아와야 할지 알려주는 용도이다. Notification.Name 형식을 지켜야 한다. object 객체를 전달할 때 쓰인다. userInfo 값을 전달할 때 쓰인다. 전달하고 싶은 정보를 userInfo 에 저장해서 전달하는 것이 일반적이다. key 와 value 값으로 전달할 수 있다. (받는 지점에서 해당키를 입력하면 벨류를 뽑아서 활용할 수 있다. 딕셔너리와 같이 사용하면 된다.)

👀 observer 등록하기

NotificationCenter.default.addObserver 공식 문서

class Person {
    let name: String

    init(name: String) {
        self.name = name
        // 알림을 받겠다고 설정
        NotificationCenter.default.addObserver(self, selector: #selector(receiveAlram), name: Notification.Name("videoArlam"), object: nil)
    }
}

NotificationCenter.default.addObserver 로 옵저버를 추가 한다. 파라미터로는 observer, selector, name, object 를 받는다.

observer 관찰자로 등록할 개체. 보통은 자기 자신이기 때문에 self 를 쓰면 된다. selector 알림을 받았을 때 수행해주는 메서드라고 이해하면 편하다. 이 메서드는 NSNotification의 인스턴스 를 파라미터로 받아야 한다. name 관찰자에게 전달하기 위해 등록할 알림의 이름이다. post 에서 지정한 이름과 같은 이름을 지정해야 그 알림을 받을 수 있다. 여러 알림이 있을 때 어떤 값을 받을 것인지 알아내는 용도이다. nil이면 발신자는 알림 이름을 배달 기준으로 사용하지 않는다. object 관찰자에게 알림을 보내는 개체이다. 이 발신자의 알림만 전달하려면 알림 발신자를 지정하면 된다. nil인 경우 알림 센터는 보낸 사람 이름을 배달 기준으로 사용하지 않는다.

🚲 Observer가 실행할 함수 만들기

class Person {
    let name: String

    init(name: String) {
        self.name = name
        NotificationCenter.default.addObserver(self, selector: #selector(receiveAlram), name: Notification.Name("youtubeNoti"), object: nil)
    }
    // 이 부분을 만들기 
    @objc func receiveAlram(notification: Notification) {
        guard let video = notification.userInfo?["mykey"] as? Video else { return }
        print("\(name)님, \(video.youtuber)의 새로운 영상이 올라왔어요. \(video.title) 보러가기")
    }
}

노티피케이션 센터가 NSObject 를 상속 받고 있기 때문에 object-C에서 사용한다는 의미로 앞에 @objc 를 붙여주어야 한다. 파라미터로 Notification 을 넣어 주어야 한다. 그럼 notification 으로 userInfo 와 object 에 접근해서 값을 사용할 수 있다. (옵셔널 바인딩 및 다운 캐스팅은 필수)

유투브 영상을 만들고 영상의 alram 메서드를 실행하면 알람이 등록되어 있던 사람들에게 값이 전달되고 자동으로 핸들러가 실행되게 된다.

let youtube = Youtube()
let redLog = Video(youtuber: "red", title: "코드치는 영상")
let silver = Person(name: "으니")
let meme = Person(name: "미미")

youtube.alram(video: redLog)
으니님, red의 새로운 영상이 올라왔어요. 코드치는 영상 보러가기
미미님, red의 새로운 영상이 올라왔어요. 코드치는 영상 보러가기

🗑 Observer 제거하기

removeObserver 공식 문서 노티피케이션 센터를 제거하지 않으면 메모리에 계속 올라가 있게 되므로, 꼭 해제를 해주어야 한다.

 deinit {
        NotificationCenter.default.removeObserver(self)
    }

지금의 경우에는 person 클래스의 인스턴스가 해제 될 때 (deinit 안에) removeObserver 을 넣어주면 될 것 같다.

😚 더욱 편하게

👍🏻 Notification.Name을 간결하게

NotificationCenter 코드를 짜다보면 post 부분에도 name 이라는 파라미터가 있고 addObserver 부분에도 name 이라는 동일한 파라미터가 있다. 이 이름값으로 내가 받으려고 하는 정보가 맞는지 확인하는 것이기 때문이다. 그런데 이 name 의 타입이 Notification.Name 이다 보니 코드에 넣으면 조금 길어진다. 이 부분을 줄일 방법이 있다.

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

Notification.Name 에게 익스텐션을 붙여주고 타입 프로퍼티로 이름을 미리 지정해 놓고 접근할 수 있도록 하는 것이다. 그러면

// 이 부분을 
NotificationCenter.default.post(name: Notification.Name("videoArlam"), object: nil, userInfo: ["mykey": video])
//이렇게 
NotificationCenter.default.post(name: .videoArlam, object: nil, userInfo: ["mykey": video])

//이 부분을 
NotificationCenter.default.addObserver(self, selector: #selector(receiveAlram), name: Notification.Name("youtubeNoti"), object: nil)
//이렇게 
NotificationCenter.default.addObserver(self, selector: #selector(receiveAlram), name: .videoArlam, object: nil)

변경이 가능하다.

🤔 object 는 언제 사용 하는 것일까?

우선 공식 문서의 설명을 읽어보면 object 파라미터는 객체를 전달한다고 쓰여있다. 지금 만든 코드에서는 Youtube 클래스로 만든 인스턴스가 하나이지만 만약에 Youtube 말고 똑같이 동영상 알림을 받는 Netflix 라는 클래스를 만들었다고 하자. Netflix 클래스 내부에는 Youtube 클래스 내부와 완전 똑같이 구현된 NotificationCenter 가 있다. 보통은 name 으로 구별을 하지만, 똑같이 동영상을 보내는 역할을 하기 때문에 name 도 videoArlam 을 동일하게 사용했다. 그래서 각각 post 부분에서 object 에 self를 넣어주었다. (자기 자신의 객체를 넣어준 것임.) 그렇다면 Person 클래스에서는 Youtube와 Netflix 에서 모두 알람이 오게 되어 있다. 같은 videoArlam 이라는 이름으로 정보를 받고 있기 때문이다. 갑자기 사람들이 나는 Youtube에서 오는 정보만 받겠어 라고 할 경우에 object 를 Youtube 로 설정해주면 (대신 반드시 보내는 곳과 같은 인스턴스 여야함) 우리의 Notification Center 는 앞으로 유투브 정보만 받는다. 이 object 를 nil 로 설정할 경우에는 그냥 필터는 없이 name 에 맞는 모든 정보를 보낸다고 생각하면 된다.

selector 에서는 userInfo 로 접근해서 값을 받지만, object 에 접근해서 그 객체(정보를 보내는) 자체에도 접근이 가능하다. 이러한 점을 이용해서 object에 객체를 보내지 않고 값을 넣어서 보내는 경우도 있다고 한다.(아직 그렇게 쓴건 못봤지만..) 애초에 정보를 거를 때 name 을 먼저 사용하니, object를 사용하는 경우가 많지는 않은 것 같다.