I’m Only Happy When It’s MVVM — Part II

Lights! Models! Guest list! Just do your best, darling!


Last time, we built a bog standard “Hello, World!” MVVM based app in SwiftUI using Combine. In this post, we’re going to query an API for some items, and render them in a grid.

We will use our existing files, as well as make more. So, open up the project we built last time, and let’s get going!

(NB: This series will focus on using SwiftUI components to achieve everything where possible, and I will try to avoid wrapping UIView objects.)


Let’s Fly!

To better separate our concerns, go ahead and make a new file for our ViewModel protocol, and move its definition in there if you haven’t already done so. We skipped doing this in Part I for the sake of brevity. However as this post is expanding upon the foundation we established last time, we should introduce some better practices.

Next, make a new Swift file and call it ServiceType. In here, we want a protocol which defines the bare minimum we’ll need to query most RESTful APIs, and an extension of the protocol to provide a default implementation of getting our data.

An example to copy pasta is attached below:

That’s right, we haven’t defined ServiceError or RequestType yet. Let’s not forget to put each of these declarations in separate files to prioritise separation of concerns.

Lastly, before we define our service to query all emoji, we need to head over and look at the documentation. Why? We’re going to define a data model! This will be used by our service, and subsequently by our ViewModel to render the view.

The documentation tells us that a returned emoji is comprised of six separate String types in a JSON object, and that the entire list is an Array. This is why our EmojiListRequest defines its Response as [Emoji].

Servicing The Engine

It’s time to build our service! Thanks to the protocol, it’s very straightforward. We need to define our baseURLString , our array of AnyCancellable , an initialiser which calls our binding function. If you hadn’t already cottoned on, it’s just like our ViewModel from Part I.

Make sure to read all the comments to understand what’s going on in more detail. Since they’re included in the gists, details have been excluded from the article to keep things brief and exciting. 😉

If there’s a better way to handle something like this in SwiftUI/Combine-land, please drop me a line!

Updating The View Model

Go ahead and replace the ViewModel from last time with the following copy pasta. We’re solely listening to our service, and taking the values into our view model.

Once you’ve done that, it’s time to update our view!

viewDidAppear 😉

Go ahead and replaceContentView with the following copy pasta.

We can see that because we are using a LazyVGrid, we’ve needed to define an array of columns. It’s set to four, because the performance of the component with more columns was a little…meh. Maybe it’s the simulator, maybe it’s SwiftUI itself. Time will tell…

Read them carefully, and make sure the Emoji type conforms to what it doesn’t yet. You’ll need a couple in there… a good id ea is to the make the id property the codeString for better reuse.

If we go ahead and run the app now, we’ll see a navigation bar, and shortly after that, a list of emoji!

(NB: Some emoji don’t render, but that could be because the host Simulator is running iOS 14.1, not iOS 14.2)

In Conclusion

With the completion of Part II, we’ve have taken a basic “Hello, World!” MVVM app, and turned it into a semi-functional real app. We copied and pasted aaaaaall the code, and that’s haaaaaaaaaaard work y’all!

If you enjoyed this post, please let me know what you think.

Catch you in Part III

Aussie iOS Engineer based in Tokyo, Japan | 日英可