Search code examples
swiftobjectinitializationdeclaration

What does`{ SomeClass().func() }()` syntax mean in a Swift declaration?


I found this somewhere and have been using it my code.

I'm not sure why the braces and the trailing parens. Are they necessary? What do they do? I'm not sure where to look in the Swift docs to find it.

var textField = { UITextField.textFieldWithInsets(insets: UIEdgeInsets(top:0, left:5, bottom:0, right:15)) }()

Solution

  • The enclosing braces and trailing parens define a closure which is immediately called, and whose return value is immediately assigned to the textField variable. This one-liner is equivalent to writing

    var textField = {
        return UITextField.textFieldWithInsets(insets: UIEdgeInsets(top:0, left:5, bottom:0, right:15))
    }()
    

    Because the closure contains only a single line, the return keyword can be omitted, and the closure was squished onto a signel line.

    In this case, the closure definition and call is entirely redundant, and this is equivalent to just writing

    var textField = UITextField.textFieldWithInsets(insets: UIEdgeInsets(top:0, left:5, bottom:0, right:15))
    

    However, this style of assigning the result of a closure to a variable is a not-uncommon way to assign the result of creating and configuring a variable across multiple lines to a resulting variable, e.g.

    var textField: UITextField = {
        let field = UITextField()
        field.font = ...
        field.textColor = ...
        field.translatesAutoresizingMasksIntoConstraints = false
        return field
    }()
    

    This style is also redundant if textField is a local variable (as you can just create the variable, then configure it), but is common when assigning a default value to an instance variable, to perform consistent setup and initialization outside of an initializer. For example:

    class MyComponent: UIView {
        // Instance variable default values are assigned
        // before initializers are called. If we assign a value here
        // then we don't need to duplicate code across our inits.
        var textField: UITextField = { /* some configuration */ }()
        
        init(text: String) {
            // textField is already initialized and configured.
            textField.text = text
        }
    
        init(someValue: Int) {
            // textField is already initialized and configured.
            textField.text = someCalculationBased(on: someValue)
        }
    }