![](/img/trans.png)
[英]Adding observer to NSNotificationCenter second time causes 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
或 init
和dealloc
addObserver
/ removeObserver
配对。
(我通常不会在viewDidLoad
放置任何KVO代码,因为它没有来自UIKit
伙伴回调)
PS:您还缺少对super.viewDidAppear()
的调用
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.