Swift - 以编程方式创建视图时的 Lazy Var 与 Let(节省内存)

Swift - Lazy Var vs. Let when creating views programmatically (saving memory)

我是初学者,我有点了解 Lazy Var 与 Let。我注意到在使用 Lazy Var 尤其是 ImageViews 时,它可以节省大量内存使用。但是到目前为止我看到的教程和指南并不经常使用 Lazy Var,所以我怀疑这是不好的做法并且我忽略了一些东西。

我做了一些调查,了解到 Lazy 不是 "thread safe,",但我不明白这是什么意思。我看过很多优缺点,但我不能得出任何结论,尤其是因为我的知识非常有限。

在创建 UIView 时,何时可以(或更好)使用 Lazy Var 与 Let?

lazy var profileImageView: UIImageView = {

    let imageView = UIImageView(image: #imageLiteral(resourceName: "page1"))
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFit
    return imageView

}()

是否使用 lazy var 取决于您的代码及其上下文。它本身并不坏或好。你必须决定什么时候合适。

在你做出决定之前,你必须知道 lazy var 是什么。

什么是 lazy var

延迟初始化是一个概念,其中变量内容的初始化(构造)被延迟到第一次使用时。首次访问此类变量会触发初始化。由于在使用(需要)变量之前不会创建内容,因此使用惰性初始化变量可以节省资源。

这是惰性初始化背后的主要驱动力。除非你需要它,否则你不会创造它。这也是您在决定是否应 lazy var 时将使用的逻辑。

如果您正在处理始终可见(需要)的视图(或其他任何东西),那么使用惰性初始化毫无意义。另一方面,当您处理并不总是需要的实例时 - 那么使用 lazy var 是合理的。

如果您的视图在呈现的视图控制器中始终可见,那么通过使其惰性化您将无济于事。如果它只在特定情况下可见——例如当用户展开一些折叠的面板时——那么让它变得懒惰是有道理的。它将使您的视图控制器加载速度更快,默认情况下使用更少的内存。


就线程安全而言,lazy var 在 Swift 中不是线程安全的。

这意味着如果两个不同的线程试图同时访问同一个 lazy var,在初始化此类变量之前,其中一个线程可能会访问部分构造的实例。

您可以在以下位置找到有关线程安全的更多信息:

Make "lazy var" threadsafe

使用 lazy var 的另一个好处是提高代码的可读性。

在您的示例中,与图像视图相关的代码组合在一起,而不是分散到初始化程序、设置函数或 viewDidLoad。通过不需要代码的 reader 冒险到代码中的不同位置来了解您的视图是如何配置的,这改进了局部推理。要了解你的观点,他们只需要跳转到它的声明。

标记为 lazy var 的初始化闭包可以访问 self,允许在闭包内进行更多配置,例如添加目标操作或引用其他常量属性。

我会考虑使用闭包初始化属性(尤其是视图)作为 lazy var 的一个好习惯,它似乎也在 Swift 社区中越来越受欢迎。

根据项目的不同,节省开发人员时间可能比节省系统内存更有价值。

惰性变量的使用可以解决一个矛盾的问题:您想创建一个自定义视图,其中包含子视图,其初始化引用父视图。

例如,如果您要创建包含相同大小的子 UIScrollView 的 UIView 的子class,则不能声明包含:

的 class
var m_scrollView: UIScrollView

override init(frame: CGRect)
{
    m_scrollView = UIScrollView(frame: self.frame)
    super.init(frame: frame)
}

编译器会抱怨您在调用 super.init 之前引用了 self。但是... super.init 必须在 所有成员初始化后 被调用。

这个循环问题的解决方案是使 m_scrollView 懒惰并在其声明中初始化它:

lazy var m_scrollView = UIScrollView(frame: self.frame)