Taking Property Wrappers to their limit š
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 typealias
:
Then, weāll start to implement our Property Wrapper GET(url:)
:
- 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 wrappedValue
:
- As the signatures suggests, the
wrappedValue
will return a function that performs an HTTP call, and return its data as aString
wrappedValue
is a computed property, meaning that we are going to build a newService
function 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 toDecodable
š
Then, we keep on implementing wrappedValue
:
- We use the
url
that was provided to our wrapper in order to callURLSession.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
completionHandler
- We donāt forget to call
task.resume()
š¤
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:
To Conclude
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