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.

How to create a draggable cookie with Swift

or: “How I learned about the default value of userInteractionEnabled on UIImageViews”…

So, today I set out to create an iPad app in which my four year old son can drag some cookies around and get to do some light math.

In order to have draggable cookies, I figured the way to go would be to derive a DraggableImageView off of UIImageView that would add to itself a UIPanGestureRecognizer that would make the cookies (or any image, really) draggable.

This was my first attempt:

but for some reason I could not get it to recognize my dragging gestures! So I messed around with the code, coding various (failed) attempts at adding UIButtons and whatnot to my DraggableImageView in order to be able to do at least one single successful addTarget, but I simply could not make it work!

I loaded up some other Swift projects where my buttons worked fine, went back to the failing DraggableImageView, messed around with platform settings and other good stuff, suspecting that it was due to a bug – it is called XCode Beta, after all – and then it hit me:

  • New image view objects are configured to disregard user events by default. If you want to handle events in a custom subclass of UIImageView, you must explicitly change the value of the userInteractionEnabled property to YES after initializing the object.”
    Source: UIImageView documentation, emphasis mine.

Right! So I went and added self.userInteractionEnabled = true in the middle, which resulted in the full code reading (with nifty hover shadow effect added)

which in turn gave me these delicious draggable cookies…. Yummy!

cookies

Playing with UIView shadows in Swift

I saw a demo somewhere, where some dude created different nifty shadow effects by tweaking the shadowPath property of UIView’s CALayer. Being pretty new to Swift and iOS development, I figured it would be fun to play around with it – here’s the result (screenshot from the iPhone simulator):

four different shadow effects

Here’s how I did it – first, I installed this simple UIViewController to display the four images:

and then I created the applyPlainShadow method (which is basically the shadow example you’ll find everywhere when you Google for “UIView drop shadow”):

Simple and neat… – but now the fun begins – let’s create that convex-piece-of-paper-on-a-surface-effect that you’ll see in many places on the web – it’s created by simply using a UIBezierPath to draw the outline of the shadow, and then setting the layer’s shadowPath to the path’s CGRect:

Neat! Lastly, let’s create a blurry oval drop shadow, as if the view was hovering high over some low surface that expands into the screen… again, I’m using the shadowPath property, initializing the UIBezierPath with the overload that creates an oval shape from a rectangle:

Nice!