Property Wrappers are one of Swift hottest new additions. In previous articles, we’ve already covered their basic usage along with more involved use case. In this article we’re taking it a bit further to find out just how far Property Wrappers can take us.
It’s always enlightening to take a look at how our neighbors get their work done. More often than not, we’ll notice they use different techniques than us to achieve the same results, and it will inspire us to improve our craft.
For instance, let’s take a look at how Android developers write networking code. In the Android realm, there’s a famous networking library called Retrofit. And the way Android developers interact with this library is unlike anything we’ve ever seen in iOS:
What’s crazy is that the code above contains the entire implementation of this HTTP call. One thing definitely stands out: there’s no actual implementation! The developer declares an
interface - the Kotlin equivalent of a
protocol, provides some relevant values through annotations and voilà: the compiler is able to synthesize the actual implementation!
Pretty cool, right? That’s definitely something that we’d love to have in Swift! Unfortunately, Swift doesn’t offer an equivalent to Kotlin Annotations. However, Swift does provide a construct that approaches them: Property Wrappers.
Property Wrappers in Swift are not as flexible as Kotlin Annotations: for instance, they cannot be used on the arguments of a function and they cannot be composed. But even with these limitations, they still pack a lot of power!
So in this article, I want to show you how we can push Property Wrappers to their limit, and implement a Retrofit-like network call 🚀
In order to keep things simple, we’ll limit ourselves to
GET HTTP calls. And our goal will be to achieve this kind of syntax:
As you probably already know, the easiest way for a network call to return its result is through a
completionHandler. And its signature tends to be very hard to follow! So to keep things simple, we begin by defining this nice
Then, we’ll start to implement our Property Wrapper
- We store the URL as part of the state of the wrapper
- To keep things simple, we crash if the string we passed is not a valid URL
Next, we’ll start to implement the required
- As the signatures suggests, the
wrappedValuewill return a function that performs an HTTP call, and return its data as a
wrappedValueis a computed property, meaning that we are going to build a new
Servicefunction every time it is accessed.
To keep the code short and to-the-point, I’ve chosen to return the data as a
String: of course, in a real world implementation we would instead use a generic type that conforms to
Then, we keep on implementing
- We use the
urlthat was provided to our wrapper in order to call
URLSession.dataTask(with:)and fire an HTTP request.
- To keep the code straightforward, we crash if there is an error when decoding the data
- We send the decoded data to the caller, through the
- We don’t forget to call
That’s it! Our Property Wrapper is now ready to be used! We can now “implement” an HTTP call simply by declaring the following:
And we can call the function
getCurrentWeather to make sure that everything works as intended:
Once again, we’ve seen that Property Wrappers are full of potential and definitely open up the way for more involved use cases than they initially let on. Still, it’s important that we are able to draw a line between a prototype and code that is production ready.
In this article, we’ve implemented a wrapper
GET(url:) that only covers a tiny part of all the cases of HTTP networking. And while we did so by pushing Property Wrappers to their limit, they are still too limited to implement a full-fledged Swift version of Retrofit.
That’s why I see the code we’ve implemented only as a prototype. And while we can absolutely take interest in the way it was implemented, I wouldn’t recommend that you actually use it your production app.
However, there must be dozens of way this technique can be efficiently applied in your code bases! And when you find one, please feel free to share it in the comments 🚀
You liked this article and you want to see more content like it? Feel free to follow me on Twitter: https://twitter.com/v_pradeilles