繁体   English   中英

为什么在取消初始化视图控制器并导致SIGABRT或EXC_BAD_ACCESS后观察者仍处于活动状态?

[英]Why observer stay alive after a view controller is deinitialized and causes SIGABRT or EXC_BAD_ACCESS?

我有一个带有两个视图控制器的简单应用程序,第一个带有按钮,以显示第二个视图控制器,第二个使用AVPlayerViewController和AVPlayer从URL播放视频。 在第二个视图控制器的viewDidAppear()中,我初始化AVPlayerViewController,配置AVPlayer并将观察者添加到AVPlayer以检测视频何时开始播放。

如果我在视频开始播放之前手动关闭了第二个视图控制器(必须迅速将其关闭,则使用缓慢的Internet连接可以帮助完成此操作),我得到一个EXC_BAD_ACCESS,因为似乎调用了watchValue(),但是在此方法(此处为容器视图)不再存在。

我必须删除deinit中的观察者才能解决此问题。 当我尝试在其他地方(例如viewWillDisappear())删除它时,有时甚至没有添加观察者,因此删除时我得到了SIGABRT(奇怪,因为我在viewDidAppear()中添加了它):

'Cannot remove an observer <App.SecondViewController 0x101805600> for the key path "status" from <AVPlayer 0x1c801a0b0> because it is not registered as an observer.'

有人知道为什么吗?

苹果文档也说:

既不保留接收此消息的对象,也不保留观察者。

为什么我需要在deinit中删除观察者? 换句话说,在我的情况下,为什么观察者在重新初始化后仍然存活?

这是第二个视图控制器的代码(第一个视图控制器仅具有用于show segue的UIButton,并且嵌入在NavigationController中):

import UIKit
import AVKit

class SecondViewController: UIViewController {
    @IBOutlet weak var containerView: UIView!

    var player: AVPlayer!

    deinit {
        //player.removeObserver(self, forKeyPath: "status")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let url = URL(string: "http://clips.vorwaerts-gmbh.de/VfE_html5.mp4")

        // Create the player and player view controller.
        player = AVPlayer(url: url!)
        let playerViewController = AVPlayerViewController()
        playerViewController.player = player

        // Add observer to detect when the video start playing.
        player.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)

        // Add the player controller in the container view.
        self.addChildViewController(playerViewController)
        self.containerView.addSubview(playerViewController.view)
        playerViewController.view.frame = containerView.bounds
        playerViewController.didMove(toParentViewController: self)

        player.play()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        player.removeObserver(self, forKeyPath: "status")
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        //player.removeObserver(self, forKeyPath: "status")
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        print("SndVC - Memory Warning")
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "status" {
            // Perform a task on the container view.
            self.containerView.backgroundColor = UIColor.purple
        }
    }
}

很难说为什么在不实际调试应用程序的情况下崩溃。 但是我会在viewWillAppear / viewDidDisappear initdealloc addObserver / removeObserver配对。

(我通常不会在viewDidLoad放置任何KVO代码,因为它没有来自UIKit伙伴回调)

PS:您还缺少对super.viewDidAppear()的调用

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM