Created
April 6, 2017 06:22
-
-
Save S2Ler/b70040538b2cec7d6462efdbf9e7ea00 to your computer and use it in GitHub Desktop.
KVO observer in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
public final class ObjectObserver<Object: NSObject>: NSObject { | |
private var observationContext = 0 | |
// MARK: - Init | |
public typealias KeyPath = String | |
private let observers: [KeyPath: (KeyPath, Object) -> Void] | |
private let observersQueue: DispatchQueue | |
public init(observers: [KeyPath: (KeyPath, Object) -> Void], | |
observersQueue: DispatchQueue) { | |
self.observers = observers | |
self.observersQueue = observersQueue | |
} | |
// MARK: - Observing | |
public var observableObject: Object? { | |
willSet { | |
removeObserving(from: observableObject) | |
} | |
didSet { | |
observeObject(observableObject) | |
} | |
} | |
private func observeObject(_ observableObject: Object?) { | |
guard let observableObject = observableObject else { | |
return | |
} | |
for keyPath in observers.keys { | |
observableObject.addObserver(self, forKeyPath: keyPath, options: [], context: &observationContext) | |
} | |
} | |
private func removeObserving(from observableObject: Object?) { | |
guard let observableObject = observableObject else { | |
return | |
} | |
for keyPath in observers.keys { | |
observableObject.removeObserver(self, forKeyPath: keyPath, context: &observationContext) | |
} | |
} | |
deinit { | |
removeObserving(from: observableObject) | |
} | |
public override func observeValue(forKeyPath keyPath: String?, | |
of object: Any?, | |
change: [NSKeyValueChangeKey: Any]?, | |
context: UnsafeMutableRawPointer?) { | |
guard context == &observationContext else { | |
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) | |
return | |
} | |
observersQueue.async { [weak self] in | |
guard let this = self else { return } | |
guard let keyPath = keyPath, | |
let handler = this.observers[keyPath], | |
let observableObject = this.observableObject else { | |
return | |
} | |
handler(keyPath, observableObject) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment