了解完系统KVO的底层原理,今天就来分析一下RxSwift的KVO源码。
直接来看下面例子,使用起来比系统KVO方便:
self.person.rx.observeWeakly(String.self, "name")
.subscribe(onNext: { (change) in
print("KVO RxSwift")
}).disposed(by: disposeBag)
对比系统KVO:
override func viewDidLoad() {
super.viewDidLoad()
self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("KVO swift")
}
deinit {
self.person.removeObserver(self, forKeyPath: "name")
}
- 我们先来看创建序列的源码:
self.person.rx.observeWeakly(String.self, "name")
extension Reactive where Base: NSObject {
public func observeWeakly<Element: RawRepresentable>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable<Element?> where Element.RawValue: KVORepresentable {
return self.observeWeakly(Element.RawValue.KVOType.self, keyPath, options: options)
.map(Element.init)
}
}
extension Reactive where Base: NSObject {
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?> {
//对keyPath处理了一下
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)
}
}
首先这里返回了observable
,重点在finishWithNilWhenDealloc(target)
,意思是当target
释放的时候会发送nil
然后销毁:
fileprivate extension ObservableType where Element == AnyObject? {
func finishWithNilWhenDealloc(_ target: NSObject)
-> Observable<AnyObject?> {
let deallocating = target.rx.deallocating
return deallocating
.map { _ in
return Observable.just(nil)
}
.startWith(self.asObservable())
.switchLatest()
}
}
- 最终返回的是一个
KVOObservable
序列(KVOObservable
继承了ObservableType
和KVOObservableProtocol
,KVOObservableProtocol
协议为序列扩展了属性能力),KVOObservable
保存了target
和keyPath
:
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
...
}
}
fileprivate final class KVOObservable<Element>
: ObservableType
, KVOObservableProtocol {
typealias Element = Element?
unowned var target: AnyObject
...
init(object: AnyObject, keyPath: String, options: KeyValueObservingOptions, retainTarget: Bool) {
self.target = object
self.keyPath = keyPath
self.options = options
self.retainTarget = retainTarget
if retainTarget { //参数为false
self.strongTarget = object
}
}
...
}
private protocol KVOObservableProtocol {
var target: AnyObject { get }
var keyPath: String { get }
var retainTarget: Bool { get }
var options: KeyValueObservingOptions { get }
}
- 最后返回的时候还用
flatMapLatest
进行了容错处理,平常监听的对象都是要用strong
修饰,做了容错处理就可以监听weak
修饰的对象:
private func observeWeaklyKeyPathFor(
_ target: NSObject,
keyPathSections: [String],
options: KeyValueObservingOptions
) -> Observable<AnyObject?> {
weak var weakTarget: AnyObject? = target //weak
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!)
///判断是否为weak
let isWeak = isWeakProperty(propertyAttributes.map(String.init) ?? "")
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 nextTarget == nil {
return Observable.just(nil)
}
let nextObject = nextTarget! as? NSObject
let strongTarget: AnyObject? = weakTarget
if nextObject == nil {
return Observable.error(RxCocoaError.invalidObjectOnKeyPath(object: nextTarget!, sourceObject: strongTarget ?? NSNull(), propertyName: propertyName))
}
if strongTarget == nil {
return Observable.empty()
}
let nextElementsObservable = keyPathSections.count == 1
? Observable.just(nextTarget)
: observeWeaklyKeyPathFor(nextObject!, keyPathSections: remainingPaths, options: options)
if isWeak {
return nextElementsObservable
.finishWithNilWhenDealloc(nextObject!)
}
else {
return nextElementsObservable
}
}
}
- 容错处理所需要的信息,有一个是通过runtime获取
target
的信息进行判断是否为weak
属性,但判断只是关键字判断(嗯,没错,系统的一些错误信息也可以这样判断,进行骚操作):
private func isWeakProperty(_ properyRuntimeInfo: String) -> Bool {
return properyRuntimeInfo.range(of: ",W,") != nil
}
- 序列创建好了,接着就是订阅了:
.subscribe(onNext: { (change) in
...
})
根据RxSwift核心逻辑,来到KVOObservable
的subscribe
函数,这里创建了KVOObserver
(KVOObserver
又继承了_RXKVOObserver
和Disposable
协议,而_RXKVOObserver
是一个OC类),在初始化时故意持有了自己造成循环引用,为了让监听能保持下去:
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
...
}
return Disposables.create(with: observer.dispose)
}
}
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 //循环引用
}
...
}
@interface _RXKVOObserver ()
@property (nonatomic, unsafe_unretained) id target;//相当于unowned
@property (nonatomic, strong ) id retainedTarget;
@property (nonatomic, copy ) NSString *keyPath;
@property (nonatomic, copy ) void (^callback)(id);
@end
@implementation _RXKVOObserver
-(instancetype)initWithTarget:(id)target
retainTarget:(BOOL)retainTarget
keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
callback:(void (^)(id))callback {
...
self.callback = callback;
// 观察者移交
[self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];
return self;
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
@synchronized(self) {
self.callback(change[NSKeyValueChangeNewKey]);
}
}
-(void)dispose {
[self.target removeObserver:self forKeyPath:self.keyPath context:nil];
self.target = nil;
self.retainedTarget = nil;
}
@end
原来在这里它实现了系统KVO的调用,清晰明了,而且不是VC
进行观察而是_RXKVOObserver
,这样的操作叫它观察者移交。target
和keyPath
就是一路传递过来的person
和name
。
- 当监听到
name
发生变化时,便会通过callback
回调出去,然后进行发送:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
@synchronized(self) {
self.callback(change[NSKeyValueChangeNewKey]);
}
}
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)
}
}
根据RxSwift核心逻辑,最终来到外面的响应闭包:
.subscribe(onNext: { (change) in
print("KVO RxSwift")
})
- 完成监听流程,接着当序列销毁的时候,根据之前了解的销毁流程,会来到
KVOObserver
的dispose
函数,然后执行super.dispose()
:
fileprivate final class KVOObserver
: _RXKVOObserver
, Disposable {
...
override func dispose() {
super.dispose()
self.retainSelf = nil //解开循环引用
}
...
}
然后来到_RXKVOObserver
的dispose
,移除监听:
-(void)dispose {
[self.target removeObserver:self forKeyPath:self.keyPath context:nil];
self.target = nil;
self.retainedTarget = nil;
}
其实内部监听写的代码不多,更多的是上层的处理。
补充
除了rx.observeWeakly
,还有一个创建监听序列的方法:
self.person.rx.observe(String.self, "name").subscribe(onNext: { (change) in
print("不常用")
}).disposed(by: disposeBag)
这个方法直接返回了KVOObservable
序列,少了很多处理,也就是简单封装了一下KVO,而且retainTarget
传递的是true
,强引用了object
,为的是不让观察目标释放(毕竟不像rx.observeWeakly
调用finishWithNilWhenDealloc(target)
对观察目标的释放进行了处理):
extension Reactive where Base: NSObject {
public func observe<Element>(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial], retainSelf: Bool = true) -> Observable<Element?> {
return KVOObservable(object: self.base, keyPath: keyPath, options: options, retainTarget: retainSelf).asObservable()
}
}
网友评论