切换到下一个视图控制器后,AVPlayer 视频仍在播放

Posted

技术标签:

【中文标题】切换到下一个视图控制器后,AVPlayer 视频仍在播放【英文标题】:AVPlayer video still playing after segue to next view controller 【发布时间】:2018-02-12 02:17:42 【问题描述】:

我目前正在循环播放我的 mp4 视频,没有播放控件,有点像 gif,但有声音。但我不知道为什么当我转到下一个视图控制器时,视频仍在播放。有人知道解决这个问题的最简单方法吗?

视图控制器

import UIKit
import AVKit
import AVFoundation
fileprivate var playerObserver: Any?


class ScoreController: UIViewController 
    @IBOutlet var label: UILabel!

    override func viewDidLoad() 
        super.viewDidLoad()


        let returnValue: Int = UserDefaults.standard.integer(forKey: "userScore")
        label.text = "Your Score: \(returnValue)/30"

        do 
            try AVAudiosession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            let path = Bundle.main.path(forResource: "Innie-Kiss", ofType:"mp4")
            let player = AVPlayer(url: URL(fileURLWithPath: path!))
            let resetPlayer = 
                player.seek(to: kCMTimeZero)
                player.play()
            
            playerObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil)  notification in resetPlayer() 
            let controller = AVPlayerViewController()
            controller.player = player
            controller.showsPlaybackControls = false
            self.addChildViewController(controller)
            let screenSize = UIScreen.main.bounds.size
            let videoFrame = CGRect(x: 0, y: 130, width: screenSize.width, height: (screenSize.height - 130) / 2)
            controller.view.frame = videoFrame
            self.view.addSubview(controller.view)
            player.play()
         catch 
        
    

    override func viewDidDisappear(_ animated: Bool) 
        super.viewDidDisappear(animated)
    
    fileprivate var player: AVPlayer? 
        didSet  player?.play() 
    
    deinit 
        guard let observer = playerObserver else  return 
        NotificationCenter.default.removeObserver(observer)
    
    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()  
    
    @IBAction func doneButton(_ sender: Any) 
        self.performSegue(withIdentifier: "done", sender: self)
    

【问题讨论】:

在移动到下一个视图控制器之前停止播放器。 什么是合适的代码? 尝试使用这个:AVAudioSession.setActive(false, with: AVAudioSessionSetActiveOptions.notifyOthersOnDeactivation) 将此代码粘贴到我的按钮操作右侧 是的,当你移动到下一个vc时,先执行这个。 【参考方案1】:

在 viewWillDisapper() 或 segue 的按钮操作中这样做:

NotificationCenter.default.removeObserver(self)

还将它从 viewDidLoad() 移动到一些函数,例如:

 var player: AVPlayer?

 func audioPlayer()
    do 
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        let path                         = Bundle.main.path(forResource: "Innie-Kiss", ofType:"mp4")
        player                           = AVPlayer(url: URL(fileURLWithPath: path!))
        let resetPlayer                  = 
            self.player?.seek(to: kCMTimeZero)
            self.player?.play()
        
        playerObserver                   = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem, queue: nil)  notification in resetPlayer() 
        let controller                   = AVPlayerViewController()
        controller.player                = player
        controller.showsPlaybackControls = false
        self.addChildViewController(controller)
        let screenSize                   = UIScreen.main.bounds.size
        let videoFrame                   = CGRect(x: 0, y: 130, width: screenSize.width, height: (screenSize.height - 130) / 2)
        controller.view.frame            = videoFrame
        self.view.addSubview(controller.view)
        player?.play()
     catch 
    

并使玩家对象成为全局变量。 var player = AVPlayer?viewWillDisappear 使其成为 nil

所以你的 viewWillDisappear 应该是这样的:

override func viewWillDisappear(_ animated: Bool) 
     NotificationCenter.default.removeObserver(self)
    if player != nil
        player?.replaceCurrentItem(with: nil)
        player = nil
    

【讨论】:

奇怪...我做了你所做的,音频仍然循环:/ 使 AVPlayerViewController 对象也成为全局对象并释放它。你能也显示你更新的内容吗? 并在播放器为零之前停止播放器。 好的,我尝试将我的 AVPlayerViewController 也设置为全局,但发生错误,您可以查看此图像以获取更多信息和我所做的代码 - ibb.co/dODigS ibb.co/jAfkvn 另外,swift 不允许 player.stop() 所以我不能这样做【参考方案2】:
override func viewWillDisappear(_ animated: Bool) 

    

如果您正在切换窗口,这可能会对您有所帮助;在执行 segue 时,您将自动执行大括号中包含的函数。我对 AV 很垃圾,但是如果它在 IBAction 中不起作用,建议关闭该功能的其他一些代码可能在这里起作用。

不过,我对 Xcode 不是很好,所以里程可能会有所不同。

【讨论】:

我确实尝试过,但无济于事。即使我去下一个视图控制器,它仍然可以听到:/【参考方案3】:

我遇到了这个问题,并通过在将 player 设置为 nil 之前添加此行来解决它:

[self.player 暂停];

这是我的观点WillDisapear:

- (void)viewWillDisappear:(BOOL)animated

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:AVPlayerItemDidPlayToEndTimeNotification
                                                  object:self.player];
    [self.player removeObserver:self forKeyPath:@"rate"];
    [self.player removeTimeObserver:self.playerObserver];
    self.playerObserver = nil;
    [self.player pause];
    self.player = nil;
    [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
    [UINavigationController attemptRotationToDeviceOrientation];
    [StayfilmApp restrictOrientation:YES];

【讨论】:

【参考方案4】:
class ScoreController: UIViewController 
    @IBOutlet var label: UILabel!
    var player: AVPlayer?

    override func viewDidLoad() 
        super.viewDidLoad()


        let returnValue: Int = UserDefaults.standard.integer(forKey: "userScore")
        label.text = "Your Score: \(returnValue)/30"

        do 
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            let path = Bundle.main.path(forResource: "Innie-Kiss", ofType:"mp4")
            player = AVPlayer(url: URL(fileURLWithPath: path!))
            let resetPlayer = 
                player.seek(to: kCMTimeZero)
                player.play()
            
            playerObserver = NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil)  notification in resetPlayer() 
            let controller = AVPlayerViewController()
            controller.player = player
            controller.showsPlaybackControls = false
            self.addChildViewController(controller)
            let screenSize = UIScreen.main.bounds.size
            let videoFrame = CGRect(x: 0, y: 130, width: screenSize.width, height: (screenSize.height - 130) / 2)
            controller.view.frame = videoFrame
            self.view.addSubview(controller.view)
            player.play()
         catch 
        
    

    override func viewDidDisappear(_ animated: Bool) 
        super.viewDidDisappear(animated)
        player.pause()
    
    fileprivate var player: AVPlayer? 
        didSet  player?.play() 
    
    deinit 
        guard let observer = playerObserver else  return 
        NotificationCenter.default.removeObserver(observer)
    
    override func didReceiveMemoryWarning() 
        super.didReceiveMemoryWarning()  
    
    @IBAction func doneButton(_ sender: Any) 
        self.performSegue(withIdentifier: "done", sender: self)
    

显着变化:

var player: AVPlayer?

还有

override func viewDidDisappear(_ animated: Bool) 
    super.viewDidDisappear(animated)
    NotificationCenter.default.removeObserver(self)
    player?.pause()

【讨论】:

【参考方案5】:

当我使用 segue 转到下一个 ViewController 时,我遇到了同样的问题,然后我通过使用此代码将当前代码与 swift 一起使用

     @IBAction func next(_ sender: Any) 


            let vc = self .storyboard?.instantiateViewController(withIdentifier:"ViewControllerAA") as! ViewControllerAA
                   self.present(vc,animated: true,completion: nil)


但问题没有解决,然后我用这段代码去下一个VC,我的问题解决了,视频的背景声音停止了,代码如下

 @IBAction func next(_ sender: Any) 


     if let vc = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerAA") as? ViewControllerAA 
         let appDelegate = UIApplication.shared.delegate as! AppDelegate
         appDelegate.window?.rootViewController = vc
      





     

【讨论】:

以上是关于切换到下一个视图控制器后,AVPlayer 视频仍在播放的主要内容,如果未能解决你的问题,请参考以下文章

AVPlayer 在后台视图控制器中缓冲视频会导致内存问题

AVPlayer replaceCurrentItemWithPlayerItem 打破 UIViewAnimation

AVPlayer 视频播放

当视频从所有屏幕完成时自动关闭 AVPlayer

在 IOS 9 上使用 AVPlayer 和 Swift 反向播放视频

AVPlayer / Airplay 按钮