【发布时间】:2017-06-17 18:08:14
【问题描述】:
编辑于 10/2020:以前的标题是“在 UIPageViewController 的 UIViewController 中未调用 Deinitializer”
我希望我的 UIViewController(s)(它是 UIPageViewController 的一部分)中的以下反初始化程序删除我的 playerLayer 并将 player 设置为 nil 以便内存不会过载(因为 @987654328当 UIViewController 可以说不再需要时,应该总是调用 @):
deinit {
self.player = nil
self.playerLayer.removeFromSuperlayer()
print("deinit")
}
为了检查deinit 是否曾被执行,我添加了 print 并发现它从未被调用过。有人可以解释为什么不调用它吗?你会建议我做什么来实现我想做的事情?
编辑:
按照 Rob(在 cmets 中)建议的 instructions in this question,我发现以下函数会导致内存泄漏。如果可以在文档目录中找到文件,则该函数应该设置播放器。
setupPlayer() 函数:
//setup video player
func setupPlayer() {
//get name of file on server //self.video is a String containing the URL for a video on a server
let fileName = URL(string: self.video!)!.lastPathComponent
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
let filePath = url.appendingPathComponent(fileName)?.path
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath!) {
//create file with name on server if not there already
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
if let docDir = paths.first
{
let appFile = docDir.appending("/" + fileName)
let videoFileUrl = URL(fileURLWithPath: appFile)
//player's video
if self.player == nil {
let playerItemToBePlayed = AVPlayerItem(url: videoFileUrl) //AVPlayerItem(url: videoFileUrl)
self.player = AVPlayer(playerItem: playerItemToBePlayed)
//add sub-layer
playerLayer = AVPlayerLayer(player: self.player)
playerLayer.frame = self.view.frame
self.controlsContainerView.layer.insertSublayer(playerLayer, at: 0)
//when are frames actually rendered (when is video loaded)
self.player?.addObserver(self, forKeyPath: "currentItem.loadedTimeRanges", options: .new, context:nil)
//loop through video
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.player?.seek(to: kCMTimeZero)
self.player?.play()
}
})
}
}
}
}
pageViewController函数(viewcontrollerAfter)
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController?
{
let currentIndexString = (viewController as! MyViewController).index
let currentIndex = indec.index(of: currentIndexString!)
//set if so that next page
if currentIndex! < indec.count - 1 {
//template
let myViewController = MyViewController()
//enter data into template
myViewController.index = self.indec[currentIndex! + 1]
//return template with data
return myViewController
}
return nil
}
编辑 2:
如您所见,没有回溯,请注意这个 malloc 的大小(右上角)和同样大的 malloc(左下角)的大小。
【问题讨论】:
-
首先,您不必在
deinit中设置nil属性。根据定义,如果调用了deinit,那么无论如何这些引用都将被释放。其次,查看控制器没有被释放,我们必须看看你的页面视图控制器是如何管理它的子控制器的。我敢打赌你会在那里保留一些参考资料。或者某处有一些强大的参考周期。仅供参考,您可以运行应用程序,然后使用“调试内存图”功能来查看是什么保持了对视图控制器的强引用。见stackoverflow.com/a/30993476/1271826 -
@Rob 我找到了导致内存泄漏的函数并将其编辑到我的答案中。可以假设是玩家。此外,我在我的问题中编辑了一个 pageviewcontroller 函数(之后的 viewcontroller),因为我无法真正看到我在哪里留下了参考资料……如果你能看一下,我将不胜感激!
-
与其倾注代码并试图猜测是什么保持对已解散视图控制器的强引用,我会在调试器中运行应用程序,做任何你希望它被释放的事情,然后使用 Xcode 的“调试内存图”功能来精确地找出是什么保持了对应该被释放的视图控制器的强引用。一旦你看到是什么保留了那个强引用,解决这个引用就会容易得多。也许与我们分享内存图图像。
-
我试图完全追溯它,但由于没有提供追溯(s.“EDIT 2”)而无法这样做。我唯一能发现的就是它一定是函数。
-
使用内存图时,我不会从
malloc块开始(因为这些通常在框架内部完成,很难与我们的代码相关联......而且可能有一些我们无法控制的微不足道的泄漏或误报)。首先关注你的对象。例如,在下面,我专注于我没有看到deinit的对象(即视图控制器),这使问题变得明显。
标签: ios swift uiviewcontroller uipageviewcontroller