Segue/unwind 反复导致加载视频时内存不断增加
Segue/unwind repeatedly causing memory to keep increasing when video is loaded
我正在编写一个非常简单的应用程序,它有两个视图控制器 - FirstVC 和 SecondVC。在 FirstVC 上,我加载了一个视频 (apples.mp4),它在后台(在我的视图中)永远循环播放。视频加载由从 FirstVC 的 viewWillAppear() 函数执行的 displayBackgroundVideo() 函数完成。
这是FirstVC的代码:
override func viewWillAppear(_ animated: Bool) {
displayBackgroundVideo()
}
func displayBackgroundVideo() {
var videoPlayer : AVPlayer?
var videoPlayerLayer : AVPlayerLayer?
let bundlePath = Bundle.main.path(forResource: "apples", ofType: "mp4")
guard bundlePath != nil else { return }
let url = URL(fileURLWithPath: bundlePath!)
let item = AVPlayerItem(url: url)
videoPlayer = AVPlayer(playerItem: item)
videoPlayerLayer = AVPlayerLayer(player: videoPlayer!)
videoPlayerLayer?.frame = CGRect(x: -self.view.frame.size.width*2, y: 0, width: self.view.frame.size.width*5, height: self.view.frame.size.height)
view.layer.insertSublayer(videoPlayerLayer!, at: 0)
videoPlayer?.playImmediately(atRate: 0.6)
// Loop video forever
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: videoPlayer?.currentItem, queue: .main)
{ _ in
videoPlayer?.seek(to: CMTime.zero)
videoPlayer?.playImmediately(atRate: 0.6)
}
}
我在 FirstVC 上也有一个按钮,如果您按下它,将转到 SecondVC。同样,在 SecondVC 中,我有一个简单的按钮,可以返回到 FirstVC。 SecondVC里没有别的了。
问题:如果我在 FirstVC -> SecondVC -> FirstVC -> SecondVC ->... 之间来回切换,我注意到内存不断增加!但是,如果我在 FirstVC 中注释掉 displayBackgroundVideo() 函数(即不加载视频),那么我会得到预期的来回行为将增加和减少内存(因为我们正在继续和展开返回成功)。
那么,为什么我播放视频时内存会爆炸(增加)?我该如何解决这个问题?
我相信你在那里造成了内存泄漏。
addObserver(forName:object:queue:using:)
实际上 returns 一个充当观察者的不透明对象,通过保留该引用,您可以在释放 VC 时在 deinit 中使用它来实际删除该观察者。
考虑到这一点,我建议更新您的代码以将设置移动到 viewDidLoad 而不是 viewWillAppear 中,并添加 deinit 以删除观察者:
class FirstVC: UIViewController {
private var backgroundVideoPlayerObj: NSObjectProtocol?
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
displayBackgroundVideo()
}
deinit {
if let backgroundVideoPlayerObj = backgroundVideoPlayerObj {
NotificationCenter.default.removeObserver(backgroundVideoPlayerObj, name: .AVPlayerItemDidPlayToEndTime, object: nil)
}
}
func displayBackgroundVideo() {
var videoPlayer : AVPlayer?
var videoPlayerLayer : AVPlayerLayer?
...
backgroundVideoPlayerObj = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: videoPlayer?.currentItem, queue: .main) { _ in
videoPlayer?.seek(to: CMTime.zero)
videoPlayer?.playImmediately(atRate: 0.6)
}
}
}
我正在编写一个非常简单的应用程序,它有两个视图控制器 - FirstVC 和 SecondVC。在 FirstVC 上,我加载了一个视频 (apples.mp4),它在后台(在我的视图中)永远循环播放。视频加载由从 FirstVC 的 viewWillAppear() 函数执行的 displayBackgroundVideo() 函数完成。
这是FirstVC的代码:
override func viewWillAppear(_ animated: Bool) {
displayBackgroundVideo()
}
func displayBackgroundVideo() {
var videoPlayer : AVPlayer?
var videoPlayerLayer : AVPlayerLayer?
let bundlePath = Bundle.main.path(forResource: "apples", ofType: "mp4")
guard bundlePath != nil else { return }
let url = URL(fileURLWithPath: bundlePath!)
let item = AVPlayerItem(url: url)
videoPlayer = AVPlayer(playerItem: item)
videoPlayerLayer = AVPlayerLayer(player: videoPlayer!)
videoPlayerLayer?.frame = CGRect(x: -self.view.frame.size.width*2, y: 0, width: self.view.frame.size.width*5, height: self.view.frame.size.height)
view.layer.insertSublayer(videoPlayerLayer!, at: 0)
videoPlayer?.playImmediately(atRate: 0.6)
// Loop video forever
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: videoPlayer?.currentItem, queue: .main)
{ _ in
videoPlayer?.seek(to: CMTime.zero)
videoPlayer?.playImmediately(atRate: 0.6)
}
}
我在 FirstVC 上也有一个按钮,如果您按下它,将转到 SecondVC。同样,在 SecondVC 中,我有一个简单的按钮,可以返回到 FirstVC。 SecondVC里没有别的了。
问题:如果我在 FirstVC -> SecondVC -> FirstVC -> SecondVC ->... 之间来回切换,我注意到内存不断增加!但是,如果我在 FirstVC 中注释掉 displayBackgroundVideo() 函数(即不加载视频),那么我会得到预期的来回行为将增加和减少内存(因为我们正在继续和展开返回成功)。
那么,为什么我播放视频时内存会爆炸(增加)?我该如何解决这个问题?
我相信你在那里造成了内存泄漏。
addObserver(forName:object:queue:using:)
实际上 returns 一个充当观察者的不透明对象,通过保留该引用,您可以在释放 VC 时在 deinit 中使用它来实际删除该观察者。
考虑到这一点,我建议更新您的代码以将设置移动到 viewDidLoad 而不是 viewWillAppear 中,并添加 deinit 以删除观察者:
class FirstVC: UIViewController {
private var backgroundVideoPlayerObj: NSObjectProtocol?
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
displayBackgroundVideo()
}
deinit {
if let backgroundVideoPlayerObj = backgroundVideoPlayerObj {
NotificationCenter.default.removeObserver(backgroundVideoPlayerObj, name: .AVPlayerItemDidPlayToEndTime, object: nil)
}
}
func displayBackgroundVideo() {
var videoPlayer : AVPlayer?
var videoPlayerLayer : AVPlayerLayer?
...
backgroundVideoPlayerObj = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: videoPlayer?.currentItem, queue: .main) { _ in
videoPlayer?.seek(to: CMTime.zero)
videoPlayer?.playImmediately(atRate: 0.6)
}
}
}