Search code examples
iosswiftgetterlazy-initialization

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.


Solution

  • 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.