3Qax
3Qax

Reputation: 354

Creating a selector with variable of function type

I am working on two views that are subclassing subclass of UITableViewCell. In the base one (subclass of UITableViewCell) I am trying to setup gesture recognizer in a way that each of super class could change the behavior (eventually call didTapped method on it's delegate) of the tap.

I have written following code. I can use #selector(tap), however I think that using a variable instead of overriding a tap method in each super class is a much cleaner way. Is it even possible to use something like #selector(tapFunc)? If no what would be the cleanest and best from engineering point of view solution?

class BaseCell: UITableViewCell {

    @objc var tapFunc: () -> () = { () in
        print("Tapped")
    }

    @objc func tap() {
        print("TEST")
    }

    func setupBasicViews(withContent: () -> ()) {

        let tapGestureRecoginzer = UITapGestureRecognizer(target: self, action: #selector(tapFunc))
        contentView.isUserInteractionEnabled = true
        contentView.addGestureRecognizer(tapGestureRecoginzer)
    }
}

And then two views that are building on top of this one:

class ViewA: BaseCell {

    //don't want to do this
    override func tap() {
        //do stuff
    }

    func setup {
        //setup everything else
    }

class ViewB: BaseCell {

   var delegate: ViewBProtocool?

    func setup {
        tapFunc = { () in
            delegate?.didTapped(self)
        }
        //setup everything else
    }

Upvotes: 2

Views: 93

Answers (1)

rmaddy
rmaddy

Reputation: 318774

You're not too far off. Make the following changes:

class BaseCell: UITableViewCell {
    var tapFunc: (() -> Void)? = nil

    // Called by tap gesture
    @objc func tap() {
        tapFunc?()
    }

    func setupBasicViews(withContent: () -> ()) {

        let tapGestureRecoginzer = UITapGestureRecognizer(target: self, action: #selector(tap))
        contentView.isUserInteractionEnabled = true
        contentView.addGestureRecognizer(tapGestureRecoginzer)
    }
}

class ViewA: BaseCell {
    func setup() {
        //setup everything else
    }
}

class ViewB: BaseCell {
    var delegate: ViewBProtocol?

    func setup() {
        tapFunc = {
            delegate?.didTapped(self)
        }
        //setup everything else
    }
}

Now each subclass can optionally provide a closure for the tapFunc property.

I show above that tapFunc is optional with no default functionality in the base class. Feel free to change that to provide some default functionality if desired.

Upvotes: 4

Related Questions