AVPlayerViewController的KVO监听playbackControlsVisibility无响应问题求助
老哥我来帮你捋捋这个问题!我之前做AVPlayer相关开发时也踩过类似的KVO不触发的坑,结合你的代码和环境(Xcode15.2 + iOS16.2),给你几个排查方向和解决方案:
最可能的核心问题:你漏了展示AVPlayerViewController的代码!
看你的play_test_video方法,只初始化了AVPlayerViewController、设置了player和监听,但完全没把这个控制器的视图添加到界面层级里(比如present或者作为子控制器嵌入)。
AVPlayerViewController的playbackControlsVisibility属性只有在控制器的视图被正确展示到界面后,才会有"显示/隐藏控件"的状态变化。如果控制器根本没被显示出来,这个属性不会有任何变更,KVO自然不会触发——连控件都没出现过,哪来的显示/隐藏事件呢?
你需要补上展示控制器的代码,比如用present的方式:
- (void)play_test_video { // 确保file_url是正确的本地/网络视频地址 g_video_test = [AVPlayer playerWithURL:file_url]; g_video_controller = [[AVPlayerViewController alloc] init]; g_video_controller.player = g_video_test; g_video_controller.delegate = self; // 关键:先把控制器展示到界面上,再添加KVO监听 [self presentViewController:g_video_controller animated:YES completion:^{ // 在控制器完全展示后再注册KVO,确保属性已处于可监听状态 [g_video_controller addObserver:self forKeyPath:@"playbackControlsVisibility" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil]; NSLog(@"... ... * observer * added"); [g_video_test play]; }]; }
如果要把AVPlayerViewController作为子控制器嵌入当前页面,就用下面的代码替代present部分:
[self addChildViewController:g_video_controller]; g_video_controller.view.frame = self.view.bounds; // 按需调整frame [self.view addSubview:g_video_controller.view]; [g_video_controller didMoveToParentViewController:self]; // 之后再添加KVO监听 [g_video_controller addObserver:self forKeyPath:@"playbackControlsVisibility" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil]; [g_video_test play];
其他排查方向
检查KVO注册时机
尽量在控制器的视图完全加载完成后再添加监听(比如上面的present completion回调、或者当前控制器的viewDidAppear:方法里),避免在控制器视图未初始化时就注册KVO,导致监听失效。验证KVO注册是否成功
可以用try-catch包裹注册代码,排查是否有隐藏的异常:@try { [g_video_controller addObserver:self forKeyPath:@"playbackControlsVisibility" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil]; NSLog(@"... ... * observer * added"); } @catch (NSException *exception) { NSLog(@"KVO注册失败:%@", exception.reason); }试试Combine替代KVO(iOS13+推荐)
如果KVO还是不好使,iOS13及以上可以用Combine框架来监听属性变化,比KVO更稳定:// 先导入Combine头文件 #import <Combine/Combine.h> // 在你的控制器里声明一个持有监听的属性(避免被提前释放) @property (nonatomic, strong) id<NSObject> playbackControlsObserver; // 替换KVO注册的代码 self.playbackControlsObserver = [g_video_controller.publisher(for: \.playbackControlsVisibility) sink(receiveValue: { isVisible in NSLog(@"*** *** video controls appear or disappear: %d", isVisible); })];
最后验证
补完展示代码后,你可以等视频播放起来,然后点击屏幕(触发控件显示/隐藏),这时候再看observeValueForKeyPath里的NSLog应该就能打印出来了。
你先按这个思路试试,有问题随时回来交流!
内容来源于stack exchange

