Segue/Unwind在视频加载时重复导致内存不断增加

3

我正在编写一个非常简单的应用程序,其中包含两个视图控制器 - 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 上我有一个按钮,如果您按下它,会 segue 到 SecondVC。同样,在 SecondVC 中,我有一个简单的按钮,可以返回到 FirstVC。SecondVC 中没有其他内容。

问题:如果我不停地在 FirstVC -> SecondVC -> FirstVC -> SecondVC ->... 之间来回跳转,我注意到内存不断增加!然而,如果我在 FirstVC 中注释掉 displayBackgroundVideo() 函数(即不加载视频),那么我会得到预期的行为,即来回跳转会增加和减少内存(因为我们成功地进行了segue和unwind)。

那么为什么显示视频会导致内存飙升?我该如何解决这个问题?

1个回答

1
我相信你在这里创建了一个内存泄漏addObserver(forName:object:queue:using:)实际上返回一个不透明对象作为观察者,并通过保留该引用,您可以在释放VC时使用它来删除该观察者。
考虑到这一点,我建议您更新代码,将设置移至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)
        }
    }

}

1
感谢@denis_lor在这方面的指导和聊天中的讨论。根据您的答案,我将代码从viewWillAppear()移动到viewDidLoad()并引入了deinit{}段,解决了问题。非常感谢您帮助我消除内存泄漏:D - atrdeveloper
2
@aheze 不是使用block-based initializer创建的观察者。这些仍然需要手动删除。 - TylerP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接