Today I Learned: Reflection in Swift
Not only are they a great tool for rapid prototyping, but, more importantly, they’re the best tool for showcasing your work, by taking advantage of rich documentation and ready-to-play-with code snippets for mobile development.
With the introduction of Swift at WWDC one year ago, came something equally revolutionary for iOS and OS X developers – playgrounds. Not only are they a great tool for rapid prototyping, but, more importantly, they’re the best tool for showcasing your work, by taking advantage of rich documentation and ready-to-play-with code snippets.
Seeing results
When developing a user-friendly playground, one thing to keep in mind is that developers love Result Views – seeing a visual representation of some abstract code you’ve written is really satisfying. To demonstrate the importance of Result View, I’m going to use the classic BananaKit framework.
Well... that’s… not very informative. A much better description would include information about banana’s taste and peel state. But can we put that content into the Result View?
Yes! That’s what mirror reflection is for.
Previously in Swift
Limited, read-only reflection APIs have been present in Swift since the very beginning. Little is known about them, as they’re poorly documented and rarely discussed. However, once mastered, they can turn out to be very handy.
There are two protocols at the core of reflection – Reflectable
and MirrorType
, the former is simply a bridge between your type and its mirror. I won’t dig deeper into the current state of reflection, so you can read more about it in this excellent NSHipster article.
New version, new possibilities
Swift 2.0 builds its reflection tools on top of what 1.2 had to offer and introduces four new protocols:
CustomStringConvertible
(previouslyPrintable
)CustomDebugStringConvertible
(previouslyDebugPrintable
)CustomReflectable
CustomPlaygroundQuickLookable
You may opt for one or all of them – it’s completely up to you. In this article, I will focus on the last two.
Mirror, mirror, on the wall…
Let’s look at the following struct representation of a 2D vector.
Nothing special here – just a couple of properties. Let’s instantiate that in our playground and set up a Result View.
Whoops, that’s a lot of zeroes and ones. And where is the length? Don’t worry, the fix is fairly simple – all you need to do is conform to CustomReflectable protocol and construct a Mirror containing your custom children.
And voilà!
You’ve got all the important information right in front of you. But wouldn’t it be great if we could actually draw the vector? That’s exactly what the second protocol is for.
…Who’s the fairest of them all?
Creating a custom Quick Look representation is almost as easy as creating a custom Mirror
. For our Vector
, we’ll just draw an arrow using a Bézier path.
The QuickLookObject
enum allows you to represent anything – from an attributed text to a sound. Let’s see what it produced in our case.
Keep in mind that Result Views will use either a Mirror
or a QuickLookObject
(preferring the latter) – you can’t show both at the same time. If you decide to go with Quick Look, it’s important to keep all useful information on screen. In our case, we should keep start and end positions.
Consider implementing this view as a homework. 😉
Reflection is still read-only
Remember that reflection in Swift is currently read-only and there’s no way to modify your program at runtime (with Objective-C-derived classes being an exception as you can still class_addMethod()
in Swift). Perhaps this limitation will be incrementally lifted in subsequent language releases. However, Swift was designed to be safe – bringing true read-write reflection would break that dogma.
Wrapping up
Reflection in Swift is still a niche topic. It gets better with every language release, yet has a long road ahead to be comparable with its Objective-C equivalent.
Right now, I encourage you to implement it so that your team and your users can better visualise your types – regardless of whether they’re representing a vector or a banana.
For more information on the topic, I recommend watching "What’s New in LLDB" session from this year’s WWDC.
The code examples in this article were written as of Swift 2.0 Beta 2 and are subject to change before the final language release.
Are you a Swift beginner or a passionate enthusiast? Either way, check out our open-source style guide. Feel free to jump in and contribute!