barndog
barndog

Reputation: 7173

Swift getter override non-computed variable

In Objective-C, it was really easy and nice to be able to do

 - (UIButton *)backButton{
      if(!_backButton){
           _backButton = [UIButton new];
      }
 }

In Swift however, when you override a property getter, it's called a computed variable and every time self.backButton is accessed, the variable is recomputed. The following example illustrates this nicely:

private var backButton: UIBarButtonItem {
    let button = UIButton(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width*0.06, height: self.view.frame.size.width*0.06))
    button.setImage(UIImage(named: "back_arrow"), forState: UIControlState.Normal)
    button.rac_signalForControlEvents(UIControlEvents.TouchUpInside).subscribeNext {
        (next: AnyObject!) -> () in
        self.navigationController?.popViewControllerAnimated(true)
        return ()
    }
    println("Recalculating the button")
    let item = UIBarButtonItem(customView: button)
    return item
}

The println statement is called every time I access self.backButton. Addtionally, the memory address printed out also changes every time. I understand that that's the nature of computed variables since they are not stored in memory.

Is this an analogous way to replicate the exact same behavior seen in Obj-C in Swift? All I want is a way to instantiate some UI variable once without having to put that code in the initialization method.

Upvotes: 1

Views: 1461

Answers (2)

Mario
Mario

Reputation: 4520

What you are referring to is called "lazy instantiation". You can reproduce it in swift using the lazy keyword:

private lazy var backButton: UIBarButtonItem = {
      let button = .....
      //....
      return button
 } ()

Upvotes: 2

David Berry
David Berry

Reputation: 41236

The best way is to probably create it as a lazy variable, that way the initializer will be called one time, the first time it's accessed.

lazy var backButton:UIBarButtonItem = {
    let button = ...
    return button
} ()

By using an initializer block, you can provide complex initialization of the instance variable.

Upvotes: 4

Related Questions