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
相关产品推荐
相关产品推荐

