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

Xcode 15升级后调用present出现NSOSStatusErrorDomain错误求助

Xcode 15升级后出现NSOSStatusErrorDomain Code=-128错误排查与解决

升级至Xcode 15后,调用视频播放逻辑时出现以下错误:
Error processing request from MAD on result: Error Domain=NSOSStatusErrorDomain Code=-128 "Request was canceled"
游戏可正常运行,但该警告持续存在。

相关代码

setupMovie方法(在viewDidLoad()中调用)

func setupMovie(theMovieName: String) {
    
    guard let path = Bundle.main.path(forResource: "movies/" + theMovieName,
                                      ofType:"mp4") else {
        print("movie not found")
        return
    }
    
    itsMoviePlayer = AVPlayer(url: URL(fileURLWithPath: path))
    itsPlayerController = AVPlayerViewController()
    itsPlayerController?.player = itsMoviePlayer
    itsMovieIsFinished = true

}   // setupMovie

playMovie与播放完成回调方法

通过playMovie(movieName: "pose")触发播放:

func playMovie(movieName: String) {
           
    NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying),
                               name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
                               object: itsPlayerController?.player?.currentItem)
    
    present(itsPlayerController!, animated:true) {
        self.itsMoviePlayer?.play()
        self.itsMovieIsFinished = false
    }

}   // playMovie

@objc func playerDidFinishPlaying(note: NSNotification) {
    
    self.dismiss(animated:true, completion:nil)
    nextScene()
    changeScene()
    
    // re-init for next time
    setupMovie(theMovieName: "pose")
    
}

排查结果

  • 不调用playMovie则无错误;
  • 完全注释playMovie中的present调用则无错误;
  • 仅注释present的闭包内容会引发其他错误;
  • 检查present语法未发现问题;
  • 上述情况针对目标设备iPad mini(第6代);
  • 若目标设备为Apple TV,还会在GameViewDidLoad中出现Unable to simultaneously satisfy constraints提示;
  • 两种设备下游戏均可正常运行,但存在上述警告;
  • 注释NotificationCenter相关代码后错误仍存在,因此present调用是最可能的问题根源。

解决建议

1. 移除强制解包,避免潜在异常

原代码中present(itsPlayerController!, animated:true)使用强制解包,若控制器初始化失败会触发异常,可能间接导致MAD请求取消错误。改用可选绑定:

func playMovie(movieName: String) {
    guard let playerController = itsPlayerController else {
        print("Player controller not initialized")
        return
    }
    
    NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying),
                                           name: .AVPlayerItemDidPlayToEndTime,
                                           object: playerController.player?.currentItem)
    
    present(playerController, animated: true) {
        self.itsMoviePlayer?.play()
        self.itsMovieIsFinished = false
    }
}

2. 规范AVPlayerViewController生命周期管理

在播放完成回调中重新初始化播放器时,需确保旧的观察者被移除,避免内存泄漏或重复监听:

deinit {
    NotificationCenter.default.removeObserver(self)
}

func playMovie(movieName: String) {
    // 添加新观察者前先移除旧的
    NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil)
    
    guard let playerController = itsPlayerController else {
        print("Player controller not initialized")
        return
    }
    
    NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying),
                                           name: .AVPlayerItemDidPlayToEndTime,
                                           object: playerController.player?.currentItem)
    
    present(playerController, animated: true) {
        self.itsMoviePlayer?.play()
        self.itsMovieIsFinished = false
    }
}

3. 优化视频资源加载方式

改用Bundle.main.url(forResource:withExtension:subdirectory:)获取视频路径,更符合AVPlayer的推荐用法,同时可监听AVPlayerItem状态确认资源加载正常:

func setupMovie(theMovieName: String) {
    guard let url = Bundle.main.url(forResource: theMovieName, withExtension: "mp4", subdirectory: "movies") else {
        print("movie not found")
        return
    }
    
    let playerItem = AVPlayerItem(url: url)
    // 监听资源加载状态
    playerItem.addObserver(self, forKeyPath: "status", options: [.new], context: nil)
    
    itsMoviePlayer = AVPlayer(playerItem: playerItem)
    itsPlayerController = AVPlayerViewController()
    itsPlayerController?.player = itsMoviePlayer
    itsMovieIsFinished = true
}

// 实现状态监听回调
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard let playerItem = object as? AVPlayerItem, keyPath == "status" else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }
    
    switch playerItem.status {
    case .readyToPlay:
        print("Video ready to play")
    case .failed:
        print("Video load failed: \(playerItem.error?.localizedDescription ?? "Unknown error")")
    case .unknown:
        print("Video status unknown")
    @unknown default:
        break
    }
}

4. 解决Apple TV约束冲突

Apple TV上的约束问题可通过设置全屏模态展示解决:

func playMovie(movieName: String) {
    guard let playerController = itsPlayerController else {
        print("Player controller not initialized")
        return
    }
    
    // 设置全屏模态,避免布局冲突
    playerController.modalPresentationStyle = .fullScreen
    
    NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying),
                                           name: .AVPlayerItemDidPlayToEndTime,
                                           object: playerController.player?.currentItem)
    
    present(playerController, animated: true) {
        self.itsMoviePlayer?.play()
        self.itsMovieIsFinished = false
    }
}

内容的提问来源于stack exchange,提问作者user22530416

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 06:50:00