在Rxswift中实现AVFoundation Looping Player example时遇到问题。 在这里的例子是添加观察者代码:
player.addObserver(self, forKeyPath: "status", options: .new, context: &ObserverContexts.playerStatus)
player.addObserver(self, forKeyPath: "currentItem", options: .old, context: &ObserverContexts.currentItem)
player.addObserver(self, forKeyPath: "currentItem.status", options: .new, context: &ObserverContexts.currentItemStatus)
player
是AVQueuePlayer
并且观察者回调代码是:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &ObserverContexts.playerStatus {
guard let newPlayerStatus = change?[.newKey] as? AVPlayerStatus else { return }
...
}
else if context == &ObserverContexts.currentItem {
guard let player = player else { return }
if player.items().isEmpty {
...
}
else {
...
if let itemRemoved = change?[.oldKey] as? AVPlayerItem {
...
}
}
}
else if context == &ObserverContexts.currentItemStatus {
guard let newPlayerItemStatus = change?[.newKey] as? AVPlayerItemStatus else { return }
...
}
else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
请注意 currentItem 值的观察者。在这种情况下,我们希望在 currentItem 更改时获得旧值。这个例子很好。
以下是Rxswift版本中的代码:
player.rx.observe(AVPlayerStatus.self, "status", options: .new)
.subscribe(onNext: { [weak self] status in
...
}).addDisposableTo(disposeBag)
player.rx.observe(AVPlayerItem.self, "currentItem", options: .old)
.subscribe(onNext: { [weak self] item in
guard let `self` = self else { return }
guard let itemRemoved = item else { return }
print("\(itemRemoved)")
}).addDisposableTo(disposeBag)
player.rx.observe(AVPlayerItemStatus.self, "currentItem.status", options: .new)
.subscribe(onNext: { [weak self] status in
...
}).addDisposableTo(disposeBag)
问题 currentItem 值的观察者总是 nil 。这让我很困惑。为什么无法使用NSKeyValueObservingOptions.old
获取旧值。
我试图找出原因。
找到以下代码(在RxCocoa / Foundation / NSObject + Rx.swift中):
fileprivate class KVOObserver
: _RXKVOObserver
, Disposable {
typealias Callback = (Any?) -> Void
var retainSelf: KVOObserver? = nil
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, callback: callback)
self.retainSelf = self
}
override func dispose() {
super.dispose()
self.retainSelf = nil
}
deinit {
#if TRACE_RESOURCES
_ = Resources.decrementTotal()
#endif
}
}
fileprivate class KVOObservable<Element>
: ObservableType
, KVOObservableProtocol {
typealias E = Element?
unowned var target: AnyObject
var strongTarget: AnyObject?
var keyPath: String
var options: NSKeyValueObservingOptions
var retainTarget: Bool
init(object: AnyObject, keyPath: String, options: NSKeyValueObservingOptions, retainTarget: Bool) {
self.target = object
self.keyPath = keyPath
self.options = options
self.retainTarget = retainTarget
if retainTarget {
self.strongTarget = object
}
}
func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == 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)
}
}
当观察者subscribe
时,会创建一个带回调的KVOObserver
。 KVOObserver
的基类是_RXKVOObserver
。
在文件(RxCocoa / Runtime / _RXKVOObserver.m)中,我找到了以下代码:
@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
在observeValueForKeyPath
func中,它只返回change[NSKeyValueChangeNewKey]
回调。当我通过NSKeyValueObservingOptions.old
键观看currentItem
更改时,显然没有任何价值。
我的问题是:我是否采用错误的方式在Rxswift中观察currentItem
的旧值?如果是这样,如何在Rxswift中观察currentItem
的旧值?