Cody Lucas Cody Lucas -3 years ago 80
Swift Question

I am defining gesture recognizers in an ImageView subclass but calling a method in the ViewController crashes with "unrecognized selector"

I am defining gesture recognizers in an ImageView subclass but calling a method in the ViewController crashes with "unrecognized selector". The gesture works if I define the gestures in the VC, but I'm trying to put the code in the custom view class to cut down on clutter.

Is this possible? This is what I'm doing:

class DetailPhotoImageView: UIImageView {

func setupGestures(){

let tapped = UITapGestureRecognizer(target: self, action: #selector(TripDetailVC.tapped(_:)))
tapped.numberOfTapsRequired = 2

addGestureRecognizer(tapped)

}
}


And then in the VC I have this function and call imageView.setupGestures()

func tapped(_ gesture:UIGestureRecognizer) {
if let tapGesture = gesture as? UITapGestureRecognizer {
switch tapGesture.numberOfTapsRequired {
case 2:
print("Worked")
default:
break
}
}
}

Answer Source

Make a protocol for your UIImageView that takes in the gesture and set your ViewController as the delegate (having the ImageView as a parameter as well is just good practice.. or common):

protocol DetailPhotoDelegate {  
    func detailPhoto(_ detailPhoto: DetailPhotoImageView, actionFor gesture: UITapGestureRecognizer)
}

Add a delegate variable to you UIImageView subclass and preform your protocol function when the view is tapped. Also, make sure your UIImageView is a UIGestureRecognizerDelegate.

class DetailPhotoImageView: UIImageView, UIGestureRecognizerDelegate {

    var delegate: DetailPhotoDelegate?

    func setupGestures() {
        let tap =  UITapGestureRecognizer(target: self, action: #selector(someAction(_:)))
        tap.delegate = self
        tap.numberOfTapsRequired = taps
        addGestureRecognizer(tap)
    }

    func someAction(_ guesture: UITapGestureRecognizer) {
        print("tap - subclass func")
        guard let aDelegate = aDelegate else { assertionFailure(); return }

        delegate.detailPhoto(self, actionFor: gesture)
    }
}

Then add the protocol to your ViewController, set it as your DetailPhotoImageView's delegate somewhere prior to the action being implemented (I did it in viewDidLoad() for the example), and implement the protocol method however you wish:

class ViewController: UIViewController, DetailPhotoDelegate {

    @IBAction weak var detailPhoto: DetailPhotoImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        detailPhoto.delegate = self
    }

    // Mark: DetailPhotoDelegate
    func detailPhoto(_ detailPhoto: DetailPhotoImageView, actionFor guesture: UITapGestureRecognizer) {

        switch guesture.numberOfTapsRequired {
        case 1: print("1 tap"); return
        case 2: print("2 taps"); return
        default: print("\(guesture.numberOfTapsRequired) taps"); return
        }
    }
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download