Taking Property Wrappers to their limit šŸš€

Vincent Pradeilles
4 min readJan 9, 2020

--

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:):

  1. We store the URL as part of the state of the wrapper
  2. 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:

  1. As the signatures suggests, the wrappedValue will return a function that performs an HTTP call, and return its data as a String
  2. wrappedValue is a computed property, meaning that we are going to build a new Service 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 to Decodable šŸ˜‰

Then, we keep on implementing wrappedValue:

  1. We use the url that was provided to our wrapper in order to call URLSession.dataTask(with:) and fire an HTTP request.
  2. To keep the code straightforward, we crash if there is an error when decoding the data
  3. We send the decoded data to the caller, through the completionHandler
  4. 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

--

--

Vincent Pradeilles

French iOS software engineer, working in Lyon, France šŸ‡«šŸ‡·https://twitter.com/v_pradeilles https://youtube.com/channel/UCjkoQk5fOk6lH-shlm53vlw