使用RxSwift
后,常常会用到KVO
,可是并无去探究底层是如何实现的,是否和swift
的KVO
实现原理相同,本文将探究RxSwift
里的KVO
的底层实现原理。编程
先看看Swift里KVO的基本使用,三步基本操做swift
//添加观察者
person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
//观察者响应回调
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
}
//移除观察者
deinit {
person.removeObserver(self, forKeyPath: "name")
}
复制代码
RxSwift
里的KVO
的基本使用,一步到位,简单粗暴api
// 序列
self.person.rx.observeWeakly(String.self, "name")
.subscribe(onNext: { (change) in
print("observeWeakly订阅到了KVO:\(String(describing: change))")
})
.disposed(by: disposeBag)
复制代码
RxSwift
通常用两种方式使用KVO
闭包
rx.observe
: 执行高效,使用的比较多,是一个KVO
机制的简单封装,只能监听Strong
属性,不然有崩溃的风险rx.observeWeakly
: 效率较低一些,由于它要处理对象的释放,防止弱引用。因此它通常使用在weak
属性上,可是能用rx.observer
的时候,也能使用rx.observeWeakly
observeWeakly
源码进入,而且继续跟踪observeWeaklyKeyPathFor
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
}
}
复制代码
observable
序列对象,点击observeWeaklyKeyPathFor
看看建立的是个什么样的observable
finishWithNilWhenDealloc
是一个容错机制,对象若是被释放就直接发送nil完成,没有观察的必要,点进去看它的方法内容可以明白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)
if !options.isDisjoint(with: .initial) {
return observable
}
else {
return observable
.skip(1)
}
}
复制代码
weak var weakTarget: AnyObject? = target
把传入进来的target
对象设置为用weak
修饰private func observeWeaklyKeyPathFor( _ target: NSObject, keyPathSections: [String], options: KeyValueObservingOptions ) -> Observable<AnyObject?> {
weak var weakTarget: AnyObject? = target
let propertyName = keyPathSections[0]
let remainingPaths = Array(keyPathSections[1..<keyPathSections.count])
let property = class_getProperty(object_getClass(target), propertyName)
if property == nil {
return Observable.error(RxCocoaError.invalidPropertyName(object: target, propertyName: propertyName))
}
let propertyAttributes = property_getAttributes(property!)
// should dealloc hook be in place if week property, or just create strong reference because it doesn't matter
let isWeak = isWeakProperty(propertyAttributes.map(String.init) ?? "")
let propertyObservable = KVOObservable(object: target, keyPath: propertyName, options: options.union(.initial), retainTarget: false) as KVOObservable<AnyObject>
// KVO recursion for value changes
// 后面代码省略,主要是一个封装容错处理
}
复制代码
isWeak
判断这个监听的属性是不是weak
, 经过判断属性值里有没有W
来判断,经过断点发现监听的name
属性是没有包含W
的private func isWeakProperty(_ properyRuntimeInfo: String) -> Bool {
return properyRuntimeInfo.range(of: ",W,") != nil
}
复制代码
KVOObservable
,点进去发现它在初始化方法里保存了须要监听的属性和对象等内容,是一个KVO保存者
ObservableType
让其具备序列的特性,KVOObservableProtocol
让其扩展几个协议属性,是面向协议编程的思路fileprivate final class KVOObservable<Element> : ObservableType , KVOObservableProtocol {
typealias Element = Element?
unowned var target: AnyObject
var strongTarget: AnyObject?
var keyPath: String
var options: KeyValueObservingOptions
var retainTarget: Bool
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
}
}
//其他代码先省略
}
复制代码
subscribe
的流程和咱们以前探索的RX流程基本同样,很是简单,直接省略这个流程来到上一步最后的KVOObservable
里的subscribe
方法KVOObserver
观察者,并跟随一个闭包,点进去看看fileprivate final class KVOObservable<Element> : ObservableType , KVOObservableProtocol {
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)
}
}
复制代码
callback
_RXKVOObserver
和Disposable
fileprivate final class KVOObserver : _RXKVOObserver , Disposable {
typealias Callback = (Any?) -> Void
var retainSelf: KVOObserver?
init(parent: KVOObservableProtocol, callback: @escaping Callback) {
#if TRACE_RESOURCES
_ = Resources.incrementTotal()
#endif
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
}
deinit {
#if TRACE_RESOURCES
_ = Resources.decrementTotal()
#endif
}
}
复制代码
_RXKVOObserver
,发现它居然是一个OC类,说明了RxSwift
的KVO
底层实现利用了OC实现的KVO
的一些相关信息self.target addObserver
最重要的一步操做是这里进行了观察者的移交操做,把VC的观察功能移交给了当前的内部类-(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;
}
复制代码
name
值变化后,回来到当前类里的下面这个方法callback
方法,而且传递了新的键值对回去-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
@synchronized(self) {
self.callback(change[NSKeyValueChangeNewKey]);
}
复制代码
callback
是在初始化时候的闭包,会流转回去observer.on
发送了响应,value
是刚刚传递过来的change[NSKeyValueChangeNewKey]
let observer = KVOObserver(parent: self) { value in
if value as? NSNull != nil {
observer.on(.next(nil))
return
}
observer.on(.next(value as? Element))
}
复制代码
subsribe
后的闭包,因此这里可以监听到这个变化,整个流程清清楚楚.subscribe(onNext: { (change) in
print("observeWeakly订阅到了KVO:\(String(describing: change))")
})
复制代码
dispose
没解析,这里调用了super
里的dispose
方法override func dispose() {
super.dispose()
self.retainSelf = nil
}
复制代码
_RXKVOObserver
里的销毁dispose
方法,能够看到在这里移除了KVO的观察者,还置nil了当前对象-(void)dispose {
[self.target removeObserver:self forKeyPath:self.keyPath context:nil];
self.target = nil;
self.retainedTarget = nil;
}
复制代码
dispose
方法,就会销毁咱们的KVO观察者RxSwift
的KVO
底层实现实际上是一个中介者模式,经过移交观察者的方式,实现序列的响应和发送效果!并发