一、简介
KVO,是Key-Value Observing的缩写,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。每次指定的被观察的对象的属性被修改后,KVO自动通知相应的观察者。
二、示范举例
因为我是在研究视频播放的时候研究的,所以这里以监听AVPlayer的状态值为例:
首先定义属性
@property (nonatomic ,strong) AVPlayer *player;
@property (nonatomic ,strong) AVPlayerItem *playerItem;
然后在viewDidLoad中对playItem的status和loadedTimeRanges这两个属性进行了监听
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *videoUrl = [NSURL URLWithString:@"http://v.jxvdy.com/sendfile/w5bgP3A8JgiQQo5l0hvoNGE2H16WbN09X-ONHPq3P3C1BISgf7C-qVs6_c8oaw3zKScO78I--b0BGFBRxlpw13sf2e54QA"];
self.playerItem = [AVPlayerItem playerItemWithURL:videoUrl];
[self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];// 监听status属性
[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];// 监听loadedTimeRanges属性
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
self.playerView.player = _player;
self.stateButton.enabled = NO;
}
然后对监听方法进行了实现:
只要监听的属性值发生了改变就会调用监听方法,这里我在方法中做了一个判断,判断当前发生改变的监听属性是status还是loadedTimeRanges,然后就可以在方法中实现监听属性发生改变时想要实现的效果了。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
AVPlayerItem *playerItem = (AVPlayerItem *)object;
if ([keyPath isEqualToString:@"status"]) {
if ([playerItem status] == AVPlayerStatusReadyToPlay) {
NSLog(@"AVPlayerStatusReadyToPlay");
self.stateButton.enabled = YES;
CMTime duration = self.playerItem.duration;// 获取视频总长度
CGFloat totalSecond = playerItem.duration.value / playerItem.duration.timescale;// 转换成秒
_totalTime = [self convertTime:totalSecond];// 转换成播放时间
[self customVideoSlider:duration];// 自定义UISlider外观
NSLog(@"movie total duration:%f",CMTimeGetSeconds(duration));
[self monitoringPlayback:self.playerItem];// 监听播放状态
} else if ([playerItem status] == AVPlayerStatusFailed) {
NSLog(@"AVPlayerStatusFailed");
}
} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
NSTimeInterval timeInterval = [self availableDuration];// 计算缓冲进度
NSLog(@"Time Interval:%f",timeInterval);
CMTime duration = _playerItem.duration;
CGFloat totalDuration = CMTimeGetSeconds(duration);
[self.videoProgress setProgress:timeInterval / totalDuration animated:YES];
}
}
尤其要注意的的一点是,KVO在使用之后还有一步必须要进行的操作,就是释放添加的观察者,无论是在MRC还是在ARC中,这是一定要进行的一步操作,不然就会引起crash。
- (void)dealloc {
[self.playerItem removeObserver:self forKeyPath:@"status" context:nil];
[self.playerItem removeObserver:self forKeyPath:@"loadedTimeRanges" context:nil];