Swift gesture recognizer that accepts a func

While doing iOS programming in Xamarin Studio, I’ve developed a pattern when working with gesture recognizers where I do something like this:

i.e. my gesture recognizers almost always work with a factory method that returns a recognizer whose callback closes over some local variables – this way, I have the full power of a dedicated class instance, but without the hazzle of defining a new class every time I need a new kind of recognizer.

I’ve messed around with Swift only a few days now, and I’m beginning to miss my closure-based recognizer pattern… but Swift (or, actually, the way Objective C is bridged) has a problem: When you addTarget on a gesture recognizer, it stores the callback – not as a Swift (UIGestureRecognizer) -> () reference, but rather as an Objective C selector-based target. This makes for a very un-Swifty feeling when adding the target, especially because it forces you to point to a method by typing its name in a string suffixed by “:”.

My first attempt towards supporting my beloved recognizer pattern in Swift was an extension on UIGestureRecognizer that would take a (UIGestureRecognizer) -> () as argument, wrap it in a class instance with an invoke method, and then do the addTarget call with that class instance – but then I got hit by the fact that the recognizer stores its callback targets with weak references, which means that my func-wrapping target would be gone by the time it was supposed to be used.

My current implementation seems to work fine though – I’ve extended UIPanGestureRecognizer to be able to be initialized with a (UIPanGestureRecognizer) -> () as its only argument, which it stores and has invoked by adding the invokeTarget method as the recognizer’s target.

This is the full code for the recognizer:

This way, I can use the recognizer like this:

which IMO makes for a pretty compact yet powerful way of creating focused and cohesive recognizers without a lot of boilerplate.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.