Stuff We Wish Was in Swift, Part 1
The Swift Programming Language is something special. It’s one of the most intuitive, least frustrating languages out there, and it grows with countless awesome features every year thanks to the huge community Apple has built. Compared to Objective-C, many things are just faster and cleaner to accomplish in Swift!
At DSW, we write 100% of our iOS software in Swift 🎉. We’re even exploring using tools like Vapor to write server-side Swift (more to come on that). But like many developers, every once in a while we find ourselves constructing useful extensions onto Swift’s built-in types that we wish were provided out of the box.
In some cases these helper methods end up being used throughout our codebase, and become key to our architecture.
In this article I’ll share some of our most frequently used helper methods and why we love having them. These methods are defined in shared frameworks and used by all of our iOS applications. Perhaps one day these will end up in Swift language proposals, but for now feel free to use and share these snippets as you see fit!
Optional Collection Subscript
The standard method of pulling an element out of a collection (e.g. array) is to use the subscript defined on
The system will throw an exception if the
Index isn’t contained in the
indices of the collection. That means we need to first validate the index, then access the element:
The example above is quite common. In many cases (such as when updating reusable UI) it is crucial to fall back to
nil if the element doesn’t exist in the collection.
How can we make this easier? Let’s add a new subscript on
Collection that converts an array out of bounds exception to
nil in one fell swoop:
.text property is already an
Optional<String>, we can now convert this to a one-liner!
As a bonus our new subscript even accepts an
Optional<Index> as input, and will propagate that
nil through the method.
We can employ this subscript anywhere we feel comfortable with a
nil result, and still use the built-in subscript everywhere else. Nice!
Easy RGBA Colors
If your designers provide colors in RGBA, you may notice that your code is littered with calls like this:
How can we shorten this method call, eliminate our copied division logic, and still keep things lightweight?
One option is to initialize with HEX values, and that is a totally valid approach depending on the scenario. However that logic requires string validation, extraction, scanning and conversion to the RGBA space. Not exactly “lightweight”.
It turns out that by using variadic function parameters we can create a super concise way to initialize colors with raw RGBA values. Check it out!
Now, creating the same RGBA color becomes as easy as:
That’s less than half the length of the original call!
Note that we’re using the
Collection[safe:]subscript from the first example to power this method. Imagine how much extra code we’d have to write without it…
We can even omit the alpha component, defining our color in RGB only if needed. This extension not only shortens our code, but also avoids math typos throughout our codebase!
Filter Optionals From Sequences
Have you ever needed to convert an
Array<MyType> and found yourself fighting with the compiler?
This trick has been requested many times by developers on StackOverflow, but we weren’t satisfied with the typically recommended solution, which is to use
flatMap). While it works in some cases, this method is built for a different purpose and can produce unintentional side effects.
We found this solution by Senseful to be a good approach. Here are some of the things we like about it:
- It only iterates over the sequence once, keeping us at O(n) complexity
- The name of the method clearly describes its effect
- It can be reliably used on multi-dimensional sequences with no side-effects
Here’s what the solution looks like:
That last extension on a non-optional
Sequenceis to help the compiler when we don’t specify the type of a sequence that actually contains optionals. It is also useful in situations involving generics.
Using this extension is super easy:
The second example would fail using
compactMap, as the result would be
[1, 2, 3, 4], not what we expected.
This helper method has been invaluable for us!
These are just a few snippets that we use on a regular basis, worth highlighting because of the impact they can have throughout a codebase. Stay tuned for Part 2 of this post, where we’ll explore a few more examples!