有没有一种好方法可以使用键值观察和阻塞?我有一个带完成块的函数,我想要在观察到的状态变为AVPlayerItemStatusReadyToPlay
时运行这个完成块。我可以以某种方式使用观察者的上下文传递块,还是会破坏KVO编程的基础?
- (void)setVideoWithURL:(NSURL *)url completed:(PlayerCompletedWithFinishedBlock)completedBlock {
...
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([change isEqual: @"AVPlayerItemStatusReadyToPlay"]) {
// Is there a way to run the completion block from here?
}
}
答案 0 :(得分:1)
只需将块存储在copy
属性中,然后使用-observeValueForKeyPath:...
方法调用它。当您移除观察结果时,不要忘记清除那个强大的参考。
添加观察者时,您确实应该为上下文使用唯一值,并且需要在-observeValueForKeyPath:...
中进行检查。但是,使用该块并不是一个好主意。首先,你仍然需要对块进行强有力的引用,因此不需要存储这样一个强大的引用。
上下文应该是对象的一种手段:a)确定对-observeValueForKeyPath:...
的调用对应于该代码自己的观察; b)以与其他代码可能设置的任何其他观察(使用-removeObserver:forKeyPath:context:
)区分的方式移除观察。因此,上下文应该识别使用它的代码,而不是任何特定的观察者或观察者。通常的方法是定义静态变量并使用其地址。
最后,即使您展示的零碎-observeValueForKeyPath:...
实施也非常糟糕。 change
永远不会等于@"AVPlayerItemStatusReadyToPlay"
,因为前者是字典而后者是字符串。除了检查上下文(如果通知不适合您的观察,还要调用super),您应该检查keyPath
或status
object
属性{/ 1}。
答案 1 :(得分:1)
Ken是对的 - 您的KVO通知处理程序(-observeValueForKeyPath
)不会按原样运行。接受他的建议
但你也应该将PlayerItem
作为属性存储在当前对象中,并确保在某个地方有匹配的-removeObserver
(可能在dealloc
中,你可以检查一下存在playerItem
,如果存在,-removeObserver
正如肯所说,你可以为completionBlock
创建一个新属性来存储它;所以稍后可以在你的KVO通知处理程序中调用它。
他还提到使用副本,并清除对您的块的强引用。这是因为通常最终会有一个保留周期,例如,例如该块来自保留它的同一个类。如果块中的代码具有对属性的引用,则它将保留拥有该属性的对象。同样的对象也保留了块,然后你将得到一个保留周期。因此,请谨慎对待您的参考资料:)