一、Swift-KVO
- 步骤一、添加观察
func swiftKVO() {
person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
}
- 步骤二、观察回调
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print(change!)
}
- 步骤三、移除观察
deinit {
person.removeObserver(self, forKeyPath: "name")
}
- 注意:监听的属性前 必须 加上 @objc dynamic
import UIKit
class Person: NSObject {
@objc dynamic var name: String = "dyz"
}
二、RxSwift-KVO
- 2.1、observe
self.person.rx.observe(String.self, "name").subscribe(onNext: { (value) in
print(value!)
}).disposed(by: disposeBag)
- 2.2、observeWeakly
self.person.rx.observeWeakly(String.self, "name").subscribe(onNext: { (value) in
print(value!)
})
.disposed(by: disposeBag)
分析 observeWeakly
#if !DISABLE_SWIZZLING && !os(Linux)
// KVO
extension Reactive where Base: NSObject {
//省略...
public func observeWeakly(_ type: Element.Type, _ keyPath: String, options: KeyValueObservingOptions = [.new, .initial]) -> Observable {
return observeWeaklyKeyPathFor(self.base, keyPath: keyPath, options: options)
.map { n in
return n as? Element
}
}
}
#endif
- target:被观察者Person
private func observeWeaklyKeyPathFor(_ target: NSObject, keyPath: String, options: KeyValueObservingOptions) -> Observable {
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)
}
}
- 点击finishWithNilWhenDealloc
fileprivate extension ObservableType where Element == AnyObject? {
func finishWithNilWhenDealloc(_ target: NSObject)
-> Observable {
let deallocating = target.rx.deallocating
return deallocating
.map { _ in
return Observable.just(nil)
}
.startWith(self.asObservable())
.switchLatest()
}
}
- 点击observeWeaklyKeyPathFor来到下面代码
- 点击KVOObservable
private func observeWeaklyKeyPathFor(
_ target: NSObject,
keyPathSections: [String],
options: KeyValueObservingOptions
) -> Observable {
weak var weakTarget: AnyObject? = target
let propertyName = keyPathSections[0]
let remainingPaths = Array(keyPathSections[1..
// KVO recursion for value changes
return propertyObservable
.flatMapLatest { (nextTarget: AnyObject?) -> Observable 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 target is alive, then send change
// if it's deallocated, don't send anything
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
}
}
}
- KVOObservable 实现了KVOObservableProtocol协议,拥有了target、keyPath、retainTarget、options等属性
- 外界调用subscribe(onNext:...),RxSwift 核心逻辑,必然会来到下面的subscribe方法
- subscribe中初始化KVOObserver观察者和保存闭包(闭包的回调是在KVO收到响应的时候)
fileprivate final class KVOObservable
: 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
}
}
func subscribe(_ 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)
}
}
fileprivate extension KeyValueObservingOptions {
var nsOptions: NSKeyValueObservingOptions {
var result: UInt = 0
if self.contains(.new) {
result |= NSKeyValueObservingOptions.new.rawValue
}
if self.contains(.initial) {
result |= NSKeyValueObservingOptions.initial.rawValue
}
return NSKeyValueObservingOptions(rawValue: result)
}
}
private protocol KVOObservableProtocol {
var target: AnyObject { get }
var keyPath: String { get }
var retainTarget: Bool { get }
var options: KeyValueObservingOptions { get }
}
- 点击KVOObserver,来到KVOObserver类,它继承_RXKVOObserver类
- 调用父类_RXKVOObserver的初始化方法,把值和闭包都传给父类
- dispose方法,会调用父类_RXKVOObserver的dispose方法,从而移除观察
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类
@interface _RXKVOObserver : NSObject
-(instancetype)initWithTarget:(id)target
retainTarget:(BOOL)retainTarget
keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
callback:(void (^)(id))callback;
-(void)dispose;
@end
- 添加观察:观察者移交
[self.target addObserver:self forKeyPath:self.keyPath options:options context:nil];
- 观察回调:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {}
,执行保存的闭包 - 移除观察:
[self.target removeObserver:self forKeyPath:self.keyPath context:nil];
@interface _RXKVOObserver ()
@property (nonatomic, unsafe_unretained) id target;
@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 = [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;
}
-(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