Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference/advantages between these two declaration styles

Tags:

ios

swift

In sample code I have seen two different styles of declaring objects. What is the advantage of one over the other?

Both are declared as var btn: UIButton!

Style 1:

btn = UIButton()
btn.translatesAutoresizingMaskIntoConstraints = false
btn.layer.borderColor = UIColor.blue.cgColor
btn.layer.borderWidth = 1
...
self.view.addSubview(btn)

Style 2:

btn = {
   let b = UIButton()
   b.translatesAutoresizingMaskIntoConstraints = false
   b.layer.borderColor = UIColor.blue.cgColor
   b.layer.borderWidth = 1
   ...
   return b
}()
self.view.addSubview(btn)

The only advantage I currently see is that the second style makes code more legible when you have many objects. You can also collapse them in Xcode. Is there any other advantage? Doesn't the second version "cost" more resources at runtime? Which is preferable?

Thanks

like image 592
Joseph Avatar asked Aug 14 '16 10:08

Joseph


2 Answers

Closure initialization (your second example) has three big advantages.

Advantage one: Initializing let structs. Your example uses a UIButton, which is a class--a reference type. If we are initializing a struct into a let, we can not mutate it. We cannot change any of its setters, nor can we call any methods marked as mutating once we initialize it into a let declaration. The closure initialization allows us to do this set up before assigning into the let-declared variable.

Advantage two: Scope. The closure we initialize with gets its own scope. It can capture variables from the enclosing scope, but variables declared within the scope are not available outside it. This means we don't have collisions on variable names. It also means that ARC could do some clean-up as our initialization completes.

Advantage three: In-line initialization of class/struct member variables. The first two advantages I listed aren't always necessary and you can usually work around them. But without closure initialization, if you wanted to initialize your button at the point it is declared, you are stuck with something like this:

class MyViewController: UIViewController {

    var button = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()

        // TODO: Set up button's properties

        view.addSubview(button)
    }
}

But with closure initialization, we can set those all set up at the point of declaration.

class MyViewController: UIViewController {

    var button: UIButton = {
        let button = UIButton()
        // TODO: Set up button
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(button)
    }
}
like image 97
nhgrif Avatar answered Oct 20 '22 05:10

nhgrif


The differences are fairly trivial in small examples but may be more significant in larger, more complex software.

In the first example, the state of btn is temporarily invalid - until all of the property assignments are complete. In the second example, the button is completely built when assigned to btn. In addition, the code in the second is, in effect, a factory method that could be separated out into a separate class and parameterised. Useful if a lot of similar buttons are being created.

Separating the responsibility for building buttons and other controls into specialist classes is an excellent step towards reducing the size and complexity of view controllers in iOS apps.

like image 25
Vince O'Sullivan Avatar answered Oct 20 '22 05:10

Vince O'Sullivan