Is there a good way to use key-value-observation and blocks together? I have a function that takes a completion block, and I want this completion block to run when the observed status changes into AVPlayerItemStatusReadyToPlay
. Can I pass the block using the context of the observer somehow, or would this break the fundamentals of KVO programming?
- (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?
}
}
Just store the block in a copy
property and call it in the -observeValueForKeyPath:...
method. Don't forget to clear that strong reference when you remove the observation.
You really should be using a unique value for the context when adding the observer and you need to check it in -observeValueForKeyPath:...
. However, it's not a good idea to use the block. For one thing, you still need to keep a strong reference to the block, so it doesn't avoid the need to store such a strong reference.
The context should be a means for an object to a) determine that a call to -observeValueForKeyPath:...
corresponds to that code's own observation; and b) remove the observation in a way that distinguishes it from any other observation that may have been set up by other code (using -removeObserver:forKeyPath:context:
). Therefore, the context should identify the code that's using it, not any specific observer or observee. The usual approach is to define a static variable and use its address.
Finally, even the fragmentary -observeValueForKeyPath:...
implementation you showed is pretty broken. change
will never be equal to @"AVPlayerItemStatusReadyToPlay"
because the former is a dictionary and the latter is a string. In addition to checking the context (and calling through to super if the notification is not for your observation), you should check the keyPath
or maybe the status
property of object
.