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~ 메소드 안에서, 메인에서 작동할 필요가 있는 코드는 메인 스레드로 가져와줘야 한다.
노티피케이션 센터는 잘 활용하면 아주아주 좋지만, 키 값도 따로 정리해 줘야 하고 코드도 분산되기 때문에 간단한 작업을 하기에는 적절하지 않을 수 있다. 전송, 수신, 등록 각자 다 해 주어야 하기 때문에!
'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 |