6

I had to create a new thread bcoz it's driving me crazy and all the other answers online are exactly the same. I have done this countless of times but I cannot see what I am missing for the life of me. I am using a "test" view controller just to get the tap gesture working but it isn't working at all... I am fairly certain that I am setting this up correctly, as this is how I've always implemented it in the past: (yes, I have checked the box for isUserInteractionEnabled). I am even implementing this on a different viewcontroller this exact way and it is working...

class TestViewController: UIViewController {

  override func viewDidLoad() {
    super.viewDidLoad()
    view.addGestureRecognizer(tap)
  }

  let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))

    
  @objc func wasTapped() {
    print("tapped")
  }
}

I have also tried adding the parameters to wasTapped:

@objc func wasTapped(gestureRecognizer: UITapGestureRecognizer) {
  print("tapped")
}
aturan23
  • 4,798
  • 4
  • 28
  • 52
user7804097
  • 308
  • 1
  • 3
  • 17

4 Answers4

14

You are saying:

override func viewDidLoad() {
    super.viewDidLoad()

    view.addGestureRecognizer(tap)
}

let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))

The problem is the last line:

let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))

You cannot just say let tap like that in the middle of nowhere. You are implicitly making an instance property. But you cannot initialize an instance property with a target of self, because self does not exist at the time an instance property is initialized. (I regard the fact that that code even compiles as a bug, and have reported it as such.)

Move that line to the start of viewDidLoad, like this:

override func viewDidLoad() {
    super.viewDidLoad()

    let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
    view.addGestureRecognizer(tap)
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Although the first answer was also correct, I am choosing this one because of the explanation. I wanted to learn why, not just how. This makes total sense and I feel silly for not thinking about that. Thank you. – user7804097 Nov 15 '17 at 05:01
  • @matt as target takes an Any? is it the case "self" is referring to the viewcontroller type here rather than the instance? – jeh Apr 12 '20 at 16:37
  • 1
    @jeh In the "buggy" version where the OP says `let tap` at the top level of the view controller, _yes_, that is exactly what `self` turns out to mean. That's the problem. – matt Apr 12 '20 at 16:48
9

Try something like this

override func viewDidLoad() {
    super.viewDidLoad()

     let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped(sender:)))
     tap.numberOfTapsRequired = 1 // Default value
     view.isUserInteractionEnabled = true
     view.addGestureRecognizer(tap)

}

@objc func wasTapped(sender: UITapGestureRecognizer) {
    print("tapped")
}
Mannopson
  • 2,634
  • 1
  • 16
  • 32
5

You have to enable interaction if you want to use gesture recognizers for standard UIView's

Add view.isUserInteractionEnabled = true in your viewDidLoad.

MQLN
  • 2,292
  • 2
  • 18
  • 33
  • This issue still occurs when isUserInteractionEnabled is set to true, FWIW. At least it does on iOS 15.4. –  Mar 23 '22 at 15:57
1
var tapGesture = UITapGestureRecognizer()

take a view and set IBOutlet like:

@IBOutlet weak var viewTap: UIView!     

Write pretty code on viewDidLoad() like:

tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.myviewTapped(_:)))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
viewTap.addGestureRecognizer(tapGesture)
viewTap.isUserInteractionEnabled = true

this method is calling when tap gesture recognized:

@objc func myviewTapped(_ sender: UITapGestureRecognizer) {
  if self.viewTap.backgroundColor == UIColor.yellow {
    self.viewTap.backgroundColor = UIColor.green
  }else{
    self.viewTap.backgroundColor = UIColor.yellow
  }
}
aturan23
  • 4,798
  • 4
  • 28
  • 52
Mr.Javed Multani
  • 12,549
  • 4
  • 53
  • 52