Combine과 KVO(Key-Value Observing)를 각각 활용하여
key-value 쌍으로 디바이스에 데이터를 저장하는 기능을 제공하는 인터페이스인 UserDefaults의 특정 Key의 변화를 비동기적으로 반영하는 방법을 알아보자!
먼저, 사용하고자 하는 key의 이름(link)과 type(String)을 지정하여 Extension을 작성해준다.
(여기서 link는 UserDefaults의 key path로 쓰인다!)
extension UserDefaults {
@objc var link: String {
get {
return string(forKey: "Link") ?? ""
}
set {
set(newValue, forKey: "Link")
}
}
}
앞서 만든 key path(\.link)를 publisher로 활용하여 구독 관계를 성립한다.
handleEvents 내부에 변화가 감지되었을 때 실행할 함수를 작성해주면 된다.
UserDefaults.standard
.publisher(for: \.link)
.handleEvents(receiveOutput: { link in
print("---> link = \(link)")
self.updateErrorMessage(isError: false, message: "이메일 인증 완료!")
})
.sink { _ in }
.store(in: &subscriptions)
let link = "[link 값]"
UserDefaults.standard.link = link
🌱 KVO
- 객체의 프로퍼티의 변경사항을 다른 객체에 알리기 위해 사용하는 코코아 프로그래밍 패턴
- Model과 View와 같이 논리적으로 분리된 파트간의 변경사항을 전달하는데 유용하다.
- NSObject를 상속한 클래스에서만 KVO를 사용할 수 있다.
변화된 UserDefaults value는
defaults를 changeHandler 클로저의 첫번째 파라미터로 선언한 경우,
defaults.[key path]로 접근할 수 있다.
var observer: NSKeyValueObservation?
init() {
observer = UserDefaults.standard.observe(\.link, changeHandler: { defaults, value in
let link = defaults.link
// print("---> link: \(link)")
if !link.isEmpty {
self.updateErrorMessage(label: self.emailErrorLabel, isError: false, message: "이메일 인증 완료!")
self.emailAuthCompleted = true
} else {
self.emailErrorLabel.text = ""
self.emailAuthCompleted = false
}
})
}
class가 종료될 때, observer를 비활성화하여 메모리 누수를 방지해야 한다.
deinit {
observer?.invalidate()
}
참고자료