在块函数中使用KVO

时间:2016-01-23 09:56:03

标签: ios objective-c-blocks key-value-observing

有没有一种好方法可以使用键值观察和阻塞?我有一个带完成块的函数,我想要在观察到的状态变为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?
    }
}

2 个答案:

答案 0 :(得分:1)

只需将块存储在copy属性中,然后使用-observeValueForKeyPath:...方法调用它。当您移除观察结果时,不要忘记清除那个强大的参考。

添加观察者时,您确实应该为上下文使用唯一值,并且需要在-observeValueForKeyPath:...中进行检查。但是,使用该块并不是一个好主意。首先,你仍然需要对块进行强有力的引用,因此不需要存储这样一个强大的引用。

上下文应该是对象的一种手段:a)确定对-observeValueForKeyPath:...的调用对应于该代码自己的观察; b)以与其他代码可能设置的任何其他观察(使用-removeObserver:forKeyPath:context:)区分的方式移除观察。因此,上下文应该识别使用它的代码,而不是任何特定的观察者或观察者。通常的方法是定义静态变量并使用其地址。

最后,即使您展示的零碎-observeValueForKeyPath:...实施也非常糟糕。 change永远不会等于@"AVPlayerItemStatusReadyToPlay",因为前者是字典而后者是字符串。除了检查上下文(如果通知不适合您的观察,还要调用super),您应该检查keyPathstatus object属性{/ 1}。

答案 1 :(得分:1)

Ken是对的 - 您的KVO通知处理程序(-observeValueForKeyPath)不会按原样运行。接受他的建议

但你也应该将PlayerItem作为属性存储在当前对象中,并确保在某个地方有匹配的-removeObserver(可能在dealloc中,你可以检查一下存在playerItem,如果存在,-removeObserver

正如肯所说,你可以为completionBlock创建一个新属性来存储它;所以稍后可以在你的KVO通知处理程序中调用它。

他还提到使用副本,并清除对您的块的强引用。这是因为通常最终会有一个保留周期,例如,例如该块来自保留它的同一个类。如果块中的代码具有对属性的引用,则它将保留拥有该属性的对象。同样的对象也保留了块,然后你将得到一个保留周期。因此,请谨慎对待您的参考资料:)