Search code examples
swiftpropertiescomputed-properties

Are computed properties evaluated every time they are accessed?


I have two questions about computed properties in Swift.

Are computed properties evaluated every time they are accessed? Or they are stored somewhere for future access?

What kind of property is this, since I couldn't google it out:

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

Is this also evaluated every time it is accessed?


Solution

  • That is NOT a computed property.

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

    It is just a stored property populated with the result of the value returned by this block of code.

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

    The block is executed when the instance of the class is instantiated. Only once.

    So writing this

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

    is equivalent to this

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

    IMHO the first approach is better because:

    • it does allow you to declared and populate a property in the same "space"
    • it's more clear
    • does prevent duplication of code if you have multiple initializers

    Note #1: Storing a closure inside a property

    As dfri noted in the comment below, the block of code does end with (). It means that the code is evaluated and the result assigned to the property.

    On the other hand, if we remove the () at the end of the block, we get something different, infact the block is not evaluated. In this case Swift tries to assign a stored closure to the property. This will produce a compile error since the property has this type UINavigationController.

    With the correct syntax we can put a closure inside a property.

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

    Now we have a sayHello property which contains a closure. The closure receives 0 parameters and does return 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
    

    Note #2: let's talk about Computed Properties

    So we made clear that code in this question is not a Computed Property. However, as EmilioPelaez noted in another comment below, we should also state that a Computed Property is evaluated each time it is accessed.

    In the example below I created a Computed Property age. As you can see each time I invoke it, the code in the block gets executed as well.

    Example of a Computed Property (age)

    enter image description here