Skip to content

Instantly share code, notes, and snippets.

@stinger
Last active October 18, 2018 11:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save stinger/e9045615e1665a8128fe0f33c8f74b8b to your computer and use it in GitHub Desktop.
Save stinger/e9045615e1665a8128fe0f33c8f74b8b to your computer and use it in GitHub Desktop.
KVO-driven model bindings
extension NSObjectProtocol where Self: NSObject {
func observe<Value>(_ keyPath: KeyPath<Self, Value>, onChange: @escaping (Value) -> ()) -> NSKeyValueObservation {
return observe(keyPath, options: [.initial, .new]) { _, change in
// TODO: change.newValue should never be `nil`, but when observing an optional property that's set to `nil`, then change.newValue is `nil` instead of `Optional(nil)`. This is the bug report for this: https://bugs.swift.org/browse/SR-6066
guard let newValue = change.newValue else { return }
onChange(newValue)
}
}
func bind<Value, Target>(_ sourceKeyPath: KeyPath<Self, Value>, to target: Target, at targetKeyPath: ReferenceWritableKeyPath<Target, Value>) -> NSKeyValueObservation {
return observe(sourceKeyPath) { target[keyPath: targetKeyPath] = $0 }
}
}
// ### Usage
class TestViewModel: NSObject {
@dynamic var title: String = "Test"
}
class TestViewController: UIViewController {
var observations: [NSKeyValueObservation] = []
override func viewDidLoad() {
super.viewDidLoad()
observations = [
viewModel.bind(\.title, to: navigationItem, at: \.title)
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment