Skip to content

Instantly share code, notes, and snippets.

@churabou
Last active February 16, 2019 16:09
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 churabou/21dc2500fd8b7e6956e06abfe6e5d124 to your computer and use it in GitHub Desktop.
Save churabou/21dc2500fd8b7e6956e06abfe6e5d124 to your computer and use it in GitHub Desktop.
Swift4 KVO data binding
@objcMembers class ViewModel: NSObject {
private (set) dynamic var count = 0
private (set) dynamic var title: String? = ""
}
final class ViewController: UIViewController {
private var bag = DisposableBag()
private let viewModel = ViewModel()
private let countLabel = UILabel()
private let titleLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.subscribe(\.count) { [weak self] count in
self?.countLabel.text = "count: \(count)"
}.dispose(by: bag)
viewModel
.bind(\.title, to: titleLabel, at: \.text)
.dispose(by: bag)
}
}
protocol Bindable { }
extension NSObject: Bindable { }
extension Bindable where Self: NSObject {
func subscribe<Value>(_ keyPath: KeyPath<Self, Value>, changeHandler: @escaping (Value) -> ()) -> Disposable {
return observe(keyPath, options: [.initial, .new]) { _, change in
guard let newValue = change.newValue else { return }
changeHandler(newValue)
}
}
func bind<Target, Value>(_ fromKeyPath: KeyPath<Self, Value>,
to target: Target,
at targetKeyPath: ReferenceWritableKeyPath<Target, Value>
) -> Disposable {
return subscribe(fromKeyPath) { newValue in
target[keyPath: targetKeyPath] = newValue
}
}
}
protocol Disposable {
func dispose()
}
extension Disposable {
func dispose(by bag: DisposableBag) {
bag.append(self)
}
}
extension NSKeyValueObservation: Disposable {}
extension Disposable where Self: NSKeyValueObservation {
func dispose() {
invalidate()
}
}
final class DisposableBag {
private var disposables: [Disposable] = []
func append(_ disposable: Disposable) {
disposables.append(disposable)
}
deinit {
disposables.forEach { $0.dispose() }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment