提到KVO,我们立刻就会想到KVO三部曲:
KVO三部曲:
//1.添加观察者
person.addObserver(self, forKeyPath: "name", options: [.old, .new], context: nil)
//2.观察者回调
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print(change!)
}
//3.移除观察者
deinit {
person.removeObserver(self, forKeyPath: "name")
}
person:
class MPerson: NSObject {
@objc dynamic var name: String = "马小撂"
}
KVO三部曲使用起来,代码的分布在不同的地方,可读性略低,相比系统的,RXSwift中的KVO就会好很多,
下面我们再来看一下RXSwift中的KVO
RXSwift中的KVO
person.rx.observe(String.self, "name")
.subscribe(onNext: { (change) in
print(change!)
}).disposed(by: disposeBag)
person.rx.observeWeakly(String.self, "name")
.subscribe(onNext: { (change) in
print(change!)
}).disposed(by: disposeBag)
相比于observe,observeWeakly,可以监听weak修饰的属性。
RXSwift中的KVO是如何实现的
第一步 还是序列的创建:
person.rx.observeWeakly(String.self, "name")
public func observeWeakly<Element>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable<Element?> {
return observeWeaklyKeyPathFor(self.base, keyPath: keyPath, options: options)
.map { n in
return n as? Element
}
}
private func observeWeaklyKeyPathFor(_ target: NSObject, keyPath: String, options: KeyValueObservingOptions) -> Observable<AnyObject?> {
let components = keyPath.components(separatedBy: ".").filter { $0 != "self" }
'let observable = observeWeaklyKeyPathFor(target, keyPathSections: components, options: options)
.finishWithNilWhenDealloc(target)'
}
observeWeaklyKeyPathFor在内部创建了一个类型为KVOObservable的序列propertyObservable。
finishWithNilWhenDealloc:当前类释放就不再监听了。
private func observeWeaklyKeyPathFor(
_ target: NSObject,
keyPathSections: [String],
options: KeyValueObservingOptions
) -> Observable<AnyObject?> {
let propertyObservable = KVOObservable(object: target, keyPath: propertyName, options: options.union(.initial), retainTarget: false) as KVOObservable<AnyObject>
return propertyObservable
.flatMapLatest { (nextTarget: AnyObject?) -> Observable<AnyObject?> in
// if target is alive, then send change
// if it's deallocated, don't send anything
}
}
再来看一下KVOObservable
fileprivate final class KVOObservable<Element>
: ObservableType
, KVOObservableProtocol {
init(object: AnyObject, keyPath: String, options: KeyValueObservingOptions, retainTarget: Bool) {
self.target = object
self.keyPath = keyPath
self.options = options
self.retainTarget = retainTarget
if retainTarget {
self.strongTarget = object
}
}
func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element? {
let observer = 'KVOObserver'(parent: self) { value in
if value as? NSNull != nil {
observer.on(.next(nil))
return
}
observer.on(.next(value as? Element))
}
return Disposables.create(with: observer.dispose)
}
}
KVOObservable初始化保存了一些基本信息,并实现了subscribe函数。
第二步,订阅
订阅时一定会来到subscribe函数,这个函数初始话了一个KVOObserver的observer,
让我们着重的看一下KVOObserver,KVO的观察者
fileprivate final class KVOObserver
: _RXKVOObserver
, Disposable {
typealias Callback = (Any?) -> Void
var retainSelf: KVOObserver?
init(parent: KVOObservableProtocol, callback: @escaping Callback) {
super.init(target: parent.target, retainTarget: parent.retainTarget, keyPath: parent.keyPath, options: parent.options.nsOptions, callback: callback)
self.retainSelf = self
}
override func dispose() {
super.dispose()
self.retainSelf = nil
}
}
KVOObserver继承_RXKVOObserver,点进去看一下
-(instancetype)initWithTarget:(id)target
retainTarget:(BOOL)retainTarget
keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
callback:(void (^)(id))callback {
self = [super init];
if (!self) return nil;
self.target = target;
if (retainTarget) {
self.retainedTarget = target;
}
self.keyPath = keyPath;
self.callback = callback;
[self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];
return self;
}
原来,_RXKVOObserver是一个OC的文件,用的是系统的添加观察者的方法。这里面对外界的信息进行了保存,并把观察者设置为我们内部的类,而不是OC的类了。
当属性发生变化时,会走面的这个方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
@synchronized(self) {
self.callback(change[NSKeyValueChangeNewKey]);
}
}
就会走我们之前保存的self.callback方法,就会来到闭包实现
第三步:发送响应
let observer = KVOObserver(parent: self) { value in
if value as? NSNull != nil {
observer.on(.next(nil))
return
}
observer.on(.next(value as? Element))
}
接着发送响应。我们就会订阅到改变的值。
而且在_RXKVOObserver这个类中我们还发现了销毁函数
-(void)dispose {
[self.target removeObserver:self forKeyPath:self.keyPath context:nil];
self.target = nil;
self.retainedTarget = nil;
}
就是说不需要开发者手动移除了。
总体来说
RxSwift中的KVO是封装了系统的KVO,将观察者交给自己的内部类,可读性强,而且不需要手动移除观察者。