Pass self as argument within init method in Swift 1.2

You can't use self unless the class is initialized. And if you would like to use self for property initialization, it must be lazy. But lazy is not supported for let, just var.

That's because:

You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

It's kind of compromise and if you can live with private setter, you can do this:

class SubView: UIView {

  private(set) lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in UIPanGestureRecognizer(target: self, action: "panAction:") }()

  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }

  func panAction(gesture: UIPanGestureRecognizer) {
  }
}

Or initialize panGestureRecognizer with just UIPanGestureRecognizer() and add target later.


The Problem

The problem is your use of let - optionals declared as let aren't given a default value of nil (var is however). The following, introduced in Swift 1.2, wouldn't be valid otherwise since you wouldn't be able to give myOptional a value after declaring it:

let myOptional: Int?

if myCondition {
    myOptional = 1
} else {
    myOptional = nil
}

Therefore, you're getting the error 'Property 'self.panGestureRecognizer' not initialized at super.init call' because before calling super.init(coder: aDecoder), because panGestureRecognizer isn't nil; it hasn't been initialised at all.

The Solutions:

1. Declare panGestureRecognizer as a var, meaning it will be given a default value of nil, which you could then change after calling super.init(coder: aDecoder).

2. In my opinion, the better solution: don't use an implicitly unwrapped optional and declare panGestureRecognizer with an initial value of UIPanGestureRecognizer(). Then set the target after super.init is called:

class SubView: UIView {
    let panGestureRecognizer = UIPanGestureRecognizer()

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        panGestureRecognizer.addTarget(self, action: Selector("panAction:"))
    }
}

Tags:

Ios

Xcode

Swift