Skip to content

Instantly share code, notes, and snippets.

@nahive
Last active February 13, 2017 11:50
Show Gist options
  • Save nahive/affe649c89e35da7fe1c500333b35a68 to your computer and use it in GitHub Desktop.
Save nahive/affe649c89e35da7fe1c500333b35a68 to your computer and use it in GitHub Desktop.
Simple observable class for Swift
import Foundation
class ObservableModel: NSObject {
private var observers: [(keypath: String, block: (Any?) -> Void)] = []
// keypath has to exist and has to have dynamic property to be notified
func observe<T>(keypath: String, with block: @escaping (T?) -> Void) {
guard let _ = value(forKeyPath: keypath) as? T else {
fatalError("value at \(keypath) is not of type \(T.self)")
}
observers.append((keypath: keypath, block: { block($0 as? T) }))
addObserver(self, forKeyPath: keypath, options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let keypath = keyPath else { return }
observers.filter { $0.keypath == keypath }.forEach {
$0.block((object as AnyObject).value(forKeyPath: keypath))
}
}
deinit {
observers.forEach { removeObserver(self, forKeyPath: $0.keypath) }
}
}
// how to use
class Model: ObservableModel {
dynamic var title: String = "Default"
}
class Holder {
private var title: String?
func present(model: Model) {
title = model.title
model.observe(keypath: #keyPath(Model.title), with: didUpdate(title:))
}
func didUpdate(title: String?) {
self.title = title
}
func debug() {
print(title)
}
}
let model = Model()
let holder = Holder()
holder.present(model: model)
holder.debug()
model.title = "New title"
holder.debug()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment