Skip to content

Instantly share code, notes, and snippets.

@danieleggert
Created March 14, 2016 08:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save danieleggert/f2f076476bb42754ee0c to your computer and use it in GitHub Desktop.
Save danieleggert/f2f076476bb42754ee0c to your computer and use it in GitHub Desktop.
Type-safe KVO
import Foundation
/// A type-safe Key-Value-Observer (KVO).
///
/// Extend the class to be observed to implement `KeyCodable`, e.g.
/// ```
/// extension WKWebView: KeyCodable {
/// enum Key: String {
/// case estimatedProgress
/// }
/// }
/// ```
/// and observe with
/// ```
/// observer = KeyValueObserver(target: webView, key: .estimatedProgress, options: []) { [weak self] progress in
/// // do something with the value
/// }
/// ```
final class KeyValueObserver<Target, Value where Target: NSObject, Target: KeyCodable, Target.Key.RawValue == String>: NSObject {
typealias blockType = ((Value) -> ())
let target: Target
let key: Target.Key
let block: blockType
private var context: Int = 0
init(target: Target, key: Target.Key, options: NSKeyValueObservingOptions, block: (Value) -> ()) {
self.target = target
self.key = key
self.block = block
super.init()
self.target.addObserver(self, forKeyPath: keyPath, options: options, context: &context)
}
deinit {
target.removeObserver(self, forKeyPath: keyPath)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?,
change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard context == context,
let object = object as? Target,
let keyPath = keyPath,
let value = object.valueForKeyPath(keyPath) as? Value else {return}
block(value)
}
}
protocol KeyCodable {
typealias Key: RawRepresentable
}
private extension KeyValueObserver {
var keyPath: String {
return key.rawValue
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment