0

I have a custom subclass of UIView. It has a pan gesture recognizer that I've set up as a required constant:

let dragger: UIPanGestureRecognizer

It's a constant because it's created once at initialization of the view and persists for the lifetime of the view.

In the view's designated initializer, init(coder), I want to create my pan gesture recognizer and wire it up. However, Under Xcode 6.3, it seems I can't do that if the gesture recognizer is a constant. (This only seems to be a problem under the Xcode 6.3 beta The code allows me to set the pan gesture initializer after the call to super.init(coder))

Since the variable is a required constant, it needs to be set up before I call the superclass init(coder). However, the only initializer for a pan gesture recognizer takes self as a parameter. Self isn't available until after I've called super.init(coder).

So, I can't create my gesture recognizer with a call to UIPanGestureRecognizer(target:action:) before the call to super.init(coder) because I need to pass self to that pan gesture initializer,

...and I can't call UIPanGestureRecognizer(target:action:) AFTER the call to super.init(coder), because I have to set values for all required constants/variables before calling the superclass initializer.

The only solution I can come up with is to make my gesture recognizer an optional var, which I'd rather not do. It will always have a value after the initializer completes, and having to unwrap an optional every time I use it is annoying.

Am I missing something here?

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • I did not test it to the end, but the compiler does not throw an error when doing this: let dragger = UIPanGestureRecognizer() – Thomas Apr 06 '15 at 13:57
  • And then what? Add a target/action to the gesture recognizer after calling `super.init(coder)`? I guess that would work, but the docs for gesture recognizers say that `UIPanGestureRecognizer(target:action:)` is the designated initializer, and you're supposed to call the designated initializer. – Duncan C Apr 06 '15 at 14:04
  • Anything prevents you form making it a lazily computed property? – Nikita Kukushkin Apr 06 '15 at 14:06
  • I could make it lazy, but my goal was to make it a required constant. lazy only works on var properties. – Duncan C Apr 06 '15 at 14:30
  • @Thomas, your solution of using the simple initializer of `UIPanGestureRecognizer()` and then adding a target/action after calling the superclass initializer is the only one I've found that lets me keep it as a required constant (let). Post your suggestion as an answer and I'll accept it. – Duncan C Apr 06 '15 at 14:32

2 Answers2

1

If the solution of aahrens does not work (maybe because of a bug), here is what I would do, even if, as you pointed out, the docs say it's not the designated way:

In your init:

dragger = UIPanGestureRecognizer()
super.init(coder)
dragger.target = self
dragger.action = <actionHandler>
Thomas
  • 2,338
  • 2
  • 23
  • 32
0

What you could do it make it implicitly unwrapped. Similar to how IBOutlets are decalred since in your case you know you're going to have a valid gesture configured. So I would declare it as

class ViewController: UIViewController {
    let dragger: UIPanGestureRecognizer!
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        dragger = UIPanGestureRecognizer(target: self, action: "mySelector:")
    }
}
aahrens
  • 5,522
  • 7
  • 39
  • 63
  • That still doesn't solve the catch-22 of having to assign it before calling the superclass initializer. – Duncan C Apr 06 '15 at 14:31
  • I wonder if that's a bug in Xcode 6.3. The code in my answer worked for me in Xcode 6.2 – aahrens Apr 06 '15 at 14:36
  • Apple's docs say they made the Swift spec more strict with 1.2. This might be an example of that, not a bug. – Duncan C Apr 09 '15 at 14:14