今天的 Widget 每次刷新都会使用更多的内存,然后最终崩溃

Today Widget uses more memory each time it refreshes, then eventually crashes

我正在开发 Today Widget,运行遇到了内存问题。

当我 运行 小部件并监视内存使用情况 Xcode 时,小部件在首次启动时使用大约 15MB。然后,当我离开小部件屏幕并返回时,它会增加到大约 16MB。

每次我滑动离开和返回时,内存使用量都会增加大约 0.5–1.5MB。当我做得更多时,我收到内存警告(调用 didReceiveMemoryWarning()),最终,随着更多的滑动,小部件崩溃了。

所有这些症状都是在 iPhone X 上测试时发生的。在模拟器上,小部件开始使用大约 50 兆字节,这看起来有点奇怪,但它在内存使用情况下具有相同的行为每次我向外滑动并向后滑动时向上滑动。

我已经尝试使用 Instruments 对此进行分析,但我只能让 Instruments 显示开始时发生的情况(当我第一次启动 Widget 时)并且它不会保持 运行ning当我来回滑动时。

通过消除过程(注释掉我的小部件的实际功能),当只剩下 UI 代码时,问题仍然存在。 这让我觉得我的 UI 方法有问题。

我过去构建过 Today Widgets,但一直使用 Interface Builder。这次我决定改为以编程方式构建界面。当我查看使用 Interface Builder 构建的其他今日小部件时,我没有看到每次刷新都会增加内存使用量的相同行为。

首先,我将所有 UI 元素设置为私有惰性变量,如下所示:

private lazy var mainStackView: UIStackView = {
    let stackView = UIStackView()
    stackView.distribution = .fillEqually
    stackView.translatesAutoresizingMaskIntoConstraints = false
    return stackView
}()

然后,在 viewDidLoad() 中,我将我的视图添加到 TodayViewController 的视图中,但有一些限制,如下所示:

view.addSubview(mainStackView)

let stackViewLeadingConstraint = mainStackView.leadingAnchor.constraintEqualToSystemSpacingAfter(view.leadingAnchor, multiplier: 1)
let stackViewTopConstraint = mainStackView.topAnchor.constraintEqualToSystemSpacingBelow(view.topAnchor, multiplier: 1)
let stackViewTrailingConstraint = view.trailingAnchor.constraintEqualToSystemSpacingAfter(mainStackView.trailingAnchor, multiplier: 1)
let stackViewBottomConstraint = view.bottomAnchor.constraintEqualToSystemSpacingBelow(mainStackView.bottomAnchor, multiplier: 1)

view.addConstraints([stackViewLeadingConstraint, stackViewTopConstraint, stackViewTrailingConstraint, stackViewBottomConstraint])

由于我是编程构建 UI 的新手,这种方法是否有任何明显不正确并且看起来可能导致内存泄漏的地方?

我什至尝试注释掉我所有的代码并运行用一个基本的空白UIViewController将其删除,其中视图生命周期函数甚至什么都不做,但我仍然有经验内存泄漏。这让我觉得当我以编程方式构建界面时我应该做一些我没有做的事情。

每次出现 Today Widget 时,似乎有些东西没有被释放并在内存中复制。 如果您能给我任何建议,我将不胜感激如何找到没有被释放的东西,强制系统释放它。谢谢!


已解决

多亏了 Christopher Pickslay 提供的疑难解答提示,我才得以找到问题所在。原来是我的错。为了解决以前不相关的问题,我在方案中打开了 Zombie Objects,而且我仍然启用了它。一旦我关闭它,问题就消失了。这是我正在谈论的设置:

我认为您构建 UI 的方式没有任何问题(根据您目前分享的内容)。尝试使用 Memory Graph Debugger 而不是 Instruments 来查找泄漏。

它将暂停调试器,您可以使用顶部栏浏览所有分配以及指向每个实例的内容。打开内存图调试器,查看您的图,然后 un-pause 并将扩展程序关闭并返回屏幕几次,然后再次打开内存图调试器。这应该能让您更好地了解泄漏的内容以及保留的内容。