【问题标题】:Are computed properties evaluated every time they are accessed?每次访问计算属性时都会对其进行评估吗?
【发布时间】:2023-03-05 02:30:02
【问题描述】:

我有两个关于 Swift 计算属性的问题。

每次访问计算属性时都会对其进行评估吗?或者它们存储在某个地方以备将来访问?

这是什么属性,我google也搜不出来:

let navigationController: UINavigationController = {
   var navigator = UINavigationController()
   navigator.navigationBar.translucent = false
   return navigator
}()

每次访问时也会评估它吗?

【问题讨论】:

    标签: swift properties computed-properties


    【解决方案1】:

    这不是计算属性。

    let navigationController: UINavigationController = {
       var navigator = UINavigationController()
       navigator.navigationBar.translucent = false
       return navigator
    }()
    

    它只是一个存储属性,填充了这段代码返回的值的结果。

    var navigator = UINavigationController()
    navigator.navigationBar.translucent = false
    return navigator
    

    当类的实例被实例化时,块被执行。只有一次。

    所以写这个

    struct Person {
        let name: String = {
            let name = "Bob"
            return name
        }() // <- look at these
    }
    

    与此等价

    struct Person {
        let name: String
        init() {
            self.name = "Bob"
        }
    }
    

    恕我直言,第一种方法更好,因为:

    • 它确实允许您在相同的“空间”中声明和填充属性
    • 清晰
    • 如果您有多个初始化程序,确实可以防止重复代码

    注意 #1:在属性中存储闭包

    正如 dfri 在下面的评论中指出的那样,代码块确实以 () 结尾。这意味着代码已求值并将结果分配给属性。

    另一方面,如果我们删除块末尾的(),我们会得到不同的结果,实际上该块是评估的。 在这种情况下,Swift 尝试将 stored closure 分配给该属性。这将产生编译错误,因为该属性的类型为 UINavigationController

    使用正确的语法,我们可以在属性中放置一个闭包。

    struct Person {
        let sayHello: ()->() = { print("Hello") }
    }
    

    现在我们有了一个包含闭包的sayHello 属性。闭包接收 0 个参数并返回 Void

    let bob = Person()
    bob.sayHello // this does NOT execute the code inside closure
    bob.sayHello() // this does execute the code in the closure and does print the message
    

    注意 #2:让我们谈谈计算属性

    所以我们明确指出,这个问题中的代码不是Computed Property。 但是,正如 EmilioPelaez 在下面的另一条评论中指出的那样,我们还应该声明Computed Property每次被访问时都会被评估。

    在下面的示例中,我创建了一个计算属性age。正如你所看到的,每次我调用它时,块中的代码也会被执行。

    计算属性示例 (age)

    【讨论】:

    • 是的,代码只执行一次。您可以在该代码块中添加print("Test") 并验证它。
    • 可能值得一提的是,最后大括号后的() 是这里的关键(通过运行匿名闭包块来初始化navigationController 属性)。例如。删除最后的()“稍微” 将顶行修改为let navigationController: () -&gt; (UINavigationController) = { ... 将产生一个存储的闭包,该闭包返回UINavigationController 实例和.translucent = false。这个闭包又可以用来代替上面的匿名块,即用闭包名称代替{ ... } 块:let myNavigationController = navigationController()
    • @dfri:我完全同意。我会在我的回答中加入这个考虑。谢谢。
    • 第一个问题的答案也应该加上,计算机属性每次访问都是计算机。
    • @appzYourLife 最后一点:我删除了(),但还必须将UINavigationController 类型替换为闭包类型... : () -&gt; (UINavigationController) = ...,而不是之前的... : UINavigationController = ...。如果我们在这里只删除(),我们会得到一个编译时错误。但是,我们可以将显式类型排除在外,让 Swift 来推断这些类型,例如对于let foo = { () -&gt; Int in 1 }(),最终的() 是将1 分配给foo(包括最终的(),=> fooInt)或将() -&gt; Int 闭包分配给foo 之间的唯一区别(省略())。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 2012-12-23
    • 2018-08-20
    • 2012-03-09
    • 2021-06-20
    相关资源
    最近更新 更多