Skip to content

Instantly share code, notes, and snippets.

@daehn
Last active July 26, 2016 22:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save daehn/4842a9c9233f7e7ade37 to your computer and use it in GitHub Desktop.
Save daehn/4842a9c9233f7e7ade37 to your computer and use it in GitHub Desktop.
Helper class to provide a typed, closure based KVO interface in Swift
import Foundation
struct Change<T>: CustomDebugStringConvertible {
let oldValue, newValue: T?
var debugDescription: String {
let prettyString: T? -> String = { return $0 != nil ? "\($0!)" : ".None" }
return "ChangeType:\n\tOld value: \(prettyString(oldValue))\n\tNew value: \(prettyString(newValue))"
}
}
final class Observer<T>: NSObject {
private let context = UnsafeMutablePointer<Void>()
typealias ChangeBlock = Change<T> -> Void
weak var object: AnyObject?
var keyPath: String
private var changeBlock: ChangeBlock
private var tornDown = false
init(object: NSObject, keyPath: String, changeType: T.Type, onChange: ChangeBlock) {
self.object = object
self.keyPath = keyPath
changeBlock = onChange
super.init()
object.addObserver(self, forKeyPath: keyPath, options:[.New, .Old], context: context)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard keyPath == self.keyPath && context == self.context else { return }
changeBlock(Change<T>(oldValue: change?["old"] as? T, newValue: change?["new"] as? T))
}
private func tearDown() {
object?.removeObserver(self, forKeyPath: keyPath, context: context)
tornDown = true
}
deinit {
assert(tornDown, "Deinit called wihtout calling tearDown first")
}
}
// Usage:
class Person: NSObject {
dynamic var name: String?
}
let max = Person()
let observer = Observer(object: max, keyPath: "name", changeType: String.self) { change in
print(change)
}
max.name = "Max"
max.name = "Bruno"
max.name = "Pierre"
observer.tearDown()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment