You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AVPlayerViewController的KVO监听playbackControlsVisibility无响应问题求助

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];

其他排查方向

  1. 检查KVO注册时机
    尽量在控制器的视图完全加载完成后再添加监听(比如上面的present completion回调、或者当前控制器的viewDidAppear:方法里),避免在控制器视图未初始化时就注册KVO,导致监听失效。

  2. 验证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);
    }
    
  3. 试试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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 11:03:12