[iOS] 연구해본 Database Event-Driven Reloading View의 후속편
잠들려고 누웠다가 문득, didSet을 잘 활용하면 데이터를 변경하는 지점에 개발자가 직접 넣어주지 않더라도 알아서 함수가 실행되게 할 수 있지 않을까? 라는 생각에 아침에 일어나자마자 실험을 다시 해봤음.
private var pushModel: Results<PushModel>! {
didSet {
occurEvent()
}
}
func occurEvent() {
for item in closures {
DispatchQueue.main.async {
item.1()
}
}
}
이런식으로 작성해보았다. 문제는.. realm의 Results는 didSet의 영향을 받지 않는다는것 이였다.
찾아보니 (WillSet/DidSet not being invoked on realm property) 모델에 뭔 짓을 하면 된다고 해서 해봤는데, 잘 안되서 빠르게 세번째 안으로..
class Model : RLMObject {
private dynamic var backingProp = 0
var prop : Int {
get {
return backingProp
}
set(newValue) {
// do willSet stuff
backingProp = newValue
// do didSet stuff
}
}
override class func ignoredProperties() -> [AnyObject]! {
return ["prop"]
}
}
NotificationToken이라는 친구를 찾았다. 애플이 만든건 아니고, Realm이친구들이 직접 만든거길래 더욱 믿음이 가서 다시 코드를 작성해보았다.
class DBObserver {
static let shared = DBObserver()
private init() {
let realm = try! Realm()
pushModel = realm.objects(PushModel.self)
token = pushModel.observe { changes in
switch changes {
case .initial, .update:
self.occurEvent()
case .error(let error):
print(error)
}
}
}
private var closures: [(AnyClass, (()->Void))] = []
private var token : NotificationToken?
private var pushModel: Results<PushModel>!
private func occurEvent() {
for item in closures {
DispatchQueue.main.async {
item.1()
}
}
}
func bind(withObject object: AnyClass, _ newClosure: @escaping ()->Void) {
for item in closures where item.0 == object { closures = closures.filter { $0.0 != object } }
print("add closure", object)
self.closures.append((object, newClosure))
}
}
이런식으로 작성, private 처리를 해놓은 덕분에 ViewController입장에서는 shared를 불러도 bind밖에 없어서 휴먼에러를 방지할수 있었고, NotificationToken도 굉장히 잘 작동하는걸 볼 수 있었다.