Menu & Search

A practical MVVM example in Swift – Part 1

May 2, 2016

The good ol’ MVC pattern has been around for a while. The acronym usually stands for Model-View-Controller, but in iOS, we’re mostly referring to Massive-View-Controller and we all know why. 1000+ line view controllers are not uncommon. And why’s that? Probably because it’s too easy to write messy view controllers. Even Apple is famous for not following the MVC pattern in their sample code.

Here’s a lovely scheme I made which shows how MVC should look like:

mvc-theory

Here’s what most of the “MVC” implementations end up looking like:

mvc-actual

On top of that, the Controller becomes massive, since it’s doing too much work.

But this post is not about MVC. We’ll be looking at MVVM, which stands for Model-View-ViewModel. In theory, it should look like:

mvvm

It even looks a lot clearer than the first one, right? The Controller now becomes in charge of displaying what the View Model offers and doesn’t care about the Model. Same goes for View – UILabels, UITextFields and UIImageViews will only show what the View Model provides.

What’s the benefit of using this, you might ask.

Well, for example – the Controller will become a lot less bloated. If we want custom formatting, manipulation with the Model data, we can easily do it in the View Model. A typical example is formatting and displaying NSDate. Usually, we’re doing that in the Controller, which means adding unnecessary code to an already bloated class. Instead, the formatting can reside in the View Model – then we know exactly which class/file is responsible for converting NSDate to String, which can then be assigned to a UILabel on the View by the Controller.

Another good reason is that your apps become more testable. You can easily write tests for View Models and specify exactly what you should expect for the user to see. Your Controllers also become more testable, because you’re forced to write more loosely coupled code.

Example

Let’s get down to it!

Model, ViewModel and Unit Test

For our example, we’ll be using a relatively simple class that represents a car. Here’s how it looks like:

Now, let’s introduce our ViewModel that we’re gonna call CarViewModel (surprise):

Note: I’ve put the CarViewModel in the same Car.swift file to keep everything a bit more confined. You can put your View Models in a separate file.

We’re gonna do some TDD now, so get ready!

A bit earlier, I mentioned that your app becomes more testable so let’s add a test that verifies our CarViewModel is doing its job properly.

Note: I’m using native Unit Testing Case classes

native-tests

Our first unit test will assert that a Ferrari F12 is properly represented by CarViewModel:

If you press ⌘+U each and every assertion will fail. That’s fine since TDD dictates we should go red/green/refactor.

Now let’s go green (even though we’re dealing with a Ferrari) and fix our CarViewModel:

We can already see the benefits of using a MVVM approach. Our Car class is straightforward as it can be, but the CarViewModel adds a bit of decoration to our plain class. For example, look at the titleText variable. It concatenates the make and model of the car. The horsepowerText adds HP (horsepower) next to the Int horsepower value of the car. The photoURL variable constructs a NSURL we can use to download the actual car photo.

⌘+U and we see our test passing, hooray! Pretty cool, right?

Refactoring

As one of the readers pointed out, the example was still missing the third step of the TDD approach – refactoring. Some might notice overly used optionals in the Car and CarViewModel classes – we don’t have to complicate our code since we structured both intializers to accept only non-optional parameters. So the refactored code looks like this:

It’s quite a bit shorter without all those guard statements, right?

PS: Because of the change to non-optionals, we do have to make one small change to the unit test as well:

That’s it, we followed the red/green/refactor TDD approach! Now on to the user interface where things get a bit more interesting.

User interface (UITableView)

To further demonstrate MVVM, let’s use an array of cars shown in a UITableView.

First, I’ll add a new class called TableViewController which is a subclass of a UITableViewController.

Screen Shot 2016-05-01 at 21.26.42

I started my project as a Single View Application so in the Main.storyboard, I’ll delete the existing View Controller and add a new UITableViewController. I set its class to my TableViewController:

Screen Shot 2016-05-01 at 21.27.31

Then, I set the cell’s reuse identifier to CarCell and the style of the cell to Right Detail (so we can display the car’s photo, title, and horsepower).

Screen Shot 2016-05-01 at 21.28.11

Time to write some code in our newly created TableViewController.

If we’re following the MVVM pattern down to the t (which we should!), our TableViewController won’t have a clue about our Car model. It only knows the CarViewModel.

In a real world application, we’d be fetching our data from an external source, but for this example, we’ll just let our AppDelegate hold an array of cars.

So, our array of cars (in AppDelegate) is actually an array of CarViewModel objects:

We have to get a hold of that in our TableViewController:

Two necessary boilerplate functions:

And the actual binding part:

The only unknown bit is the loadImage function which is not that important for our sample, but we don’t want to block the main thread while we’re loading image data. At this point, I usually use something like Alamofire to help me with downloading images, but I don’t want to complicate the example too much, so we’re just gonna roll with the basic implementation:

Note: if you’re following this example, you have to add a key to your Info.plist, otherwise images won’t be loaded from non-secure locations:

This concludes our TableViewController. If I run the app, I see that the table view is properly displaying my array of cars (it would be nice if it were an actual array of my cars … in my garage):

Simulator Screen Shot 01 May 2016 21.35.44

To top the first part off, let’s write a simple UI test just to make sure everything works:

Everything is A-ok! So why the tests, you might ask?

Drum roll … data source changes!

This was so simple that we have to complicate things a bit to make it interesting. 🙂

Let’s say our Car model has to change for some reason. Our data source changed from returning horsepower to returning kilowatts. First, we change the Car model and replace horsepower with kilowatts:

We’ll see we have to make some changes the CarViewModel as well, since our tests expect horsepowerText, not kilowattsTexts:

Of course, we have to change the initializers throughout the app, otherwise we’ll get build errors (since Car’s init function changed to accept kilowatts instead of horsepower):

If we run tests (⌘+U), we’ll see that everything still works (unit and UI tests) and although our data source changed, our Controller (TableViewController) stayed the same, since it really doesn’t care about the Model. As long as the ViewModel (CarViewModel) has the expected variables, we’re fine.

The fully working project is waiting for you on GitHub. (You can also download a zipped version here)

Next time …

Most of the apps require some kind of user interaction, which means that your Controller will also be responsible for passing updates back to the View Model, which will have to update the Model itself. This is a perfect job for a binding mechanism. We’re going to cover this in part 2 so make sure you leave your email and get notified when it goes live.

Thanks for reading this!

UPDATE: Part 2 with RxSwift implementation is now available!

STOP LOSING TIME WITH AUTO LAYOUT!

Take part in the 5-day course with actionable tasks that will let you become a master at recognizing and solving the most common mistakes iOS developers do with Auto Layout.

Let Auto Layout become a tool you swing with your utmost confidence!

I won't send you spam, I promise. Unsubscribe at any time. Powered by ConvertKit
Hey there! You're already subscribed to my newsletter and you've hopefully gotten some useful tips and tricks when working with iOS. If you're also working with Auto Layout, make sure to check out my book called Auto Layout Fundamentals and get a 20% off for being my subscriber! https://gum.co/autolayoutfundamentals/youareawesome
Jure Zove

A lot of things but mostly a programmer who really likes fast cars. Check me out on Twitter, if you fancy.

Related article

How to properly do buttons in table view cells using Swift closures

Note: This post is an upgrade of the original post…

A practical MVVM example in Swift – Part 2 (featuring RxSwift)

Welcome to part 2 of the practical MVVM example in…

Supporting links in text

If you’ve encountered a use case where you need a…

  • Thanks man, nice article.

  • J a c k O ‘ N e i l l

    Merci !

  • Ippo

    Excellent introduction to MVVM.
    Thank you very much man!

  • |Koki|Tweep|

    Nice and clear article, Thank you

  • Pauline Sihawong

    Hello Jure, I’m just new to MVVM. Your example is just exactly what I’m interesting in – How ViewModel manage an array of Models. What do you think if it better to make CarViewModel in this example to hold array of cars? Is it can do more in that case I’m just not sure.
    Thanks in advanced 🙂

    • Hey Pauline!

      CarViewModel should generally represent only one instance since it’s used as a connection between one specific car and one specific view.

      A controller is a perfect place to hold an array of cars, since the controller coordinates the creation of the CarViewModel.

      However, if you want to hold an array of let’s say – car passengers, then the CarViewModel would be a perfect place to set it up. 🙂

      Let me know if this helps!

      • Pauline Sihawong

        Thanks for your reply!!

        I got your idea but currently I’m confuse about what exactly ViewModel class should do.. One is yours, in this example I see your CarViewModel represent a model plus presentation logic. Some others, they said ViewModel could even have method to handle event (may be tap event, delete event etc.).

        How is the different? I think maybe both is suitable for different condition but may be I have to understand more in the underlying concept between them. So, I know when to select one approach or another.

        If you have any ideas base on my confusion. Please let me know 🙂

        • Yes, the ViewModel can also handle the interactions (taps, swipes, etc), but the ViewController is more suited for that. ViewModel shouldn’t generally be aware of what the UI is doing. The Controller should intercepts the interaction and then fires off events like “changeValueX” on the ViewModel, which can then do something with the actual Model.

          So again, I would generally avoid doing any kind of UI stuff in the ViewModel, because it’s main purpose is to serve as a connection between the View and the Model, but the Controller is the one that should be a connection between the user and the View.

          Does that make sense?

  • kocyigityunus

    That’s a very bad UITableViewCell usage.

    You must clear view cell’s state (images, texts ) before use.
    And you should never, never, never use non cancelable (gcd) jobs directly on a reusable view. ( uitableviewcell ).

    • Well, downloading images is definitely better handled with a dedicated library (like I said in the post), but this is just an example and it’s secondary to the principle this post is trying to show.
      That would also clear the image view’s state, but I think clearing labels is a bit unnecessary since there’s no async loading going on. When the cells are reused, the text change should be instantaneous.

  • thanks for this very interesting article! I have one question though, that is not directly related to the mvvm topic.

    I see that you are using vars with closures to return the data you need. It not the first time I see that, but I was wondering why you’re using that and not getter functions like getModel() -> String.

    Maybe I’m missing something (I’m pretty new to swift dev) so some enlightenment would be greatly appreciated! 🙂

    • Hey there! Which class are you referring to? The CarViewModel?

      • yes. 🙂

        • Oh from my part, it’s mostly aesthetics – saying carViewModel.makeText reads a bit better than carViewModel.getMakeText(). A function is kind of unnecessary since we usually introduce functions when we want to do something. Here, we’re just returning a value.
          Hope this is a satisfying answer! 🙂

  • Matt

    Great article, it is the first one that actually helps me understanding how to apply the concept in Swift.
    I have one question related to the data (which you simply load from the AppDelegate in the example)
    Where would you put connections to the database, APIs etc. e.g. Firebase Datebase, Authentication Services? I am wondering if it makes sense to put this into the Controllers or to have a separate area, such as a DataServices class taking care of all these “connections”.
    What do you think? Thanks!

    • Thanks!

      I usually create a separate class, for example API.swift or _your_app_name_API.swift. Same with a database. This approach can drastically reduce complexity in controllers and is easily reusable. That said, you still have to be careful not to couple things too tightly – the API or DataServices class should always return objects that are ready to use – it shouldn’t be exposing any of the fetching/reading mechanism to the user.

      Hope this helps. 🙂

  • Marq

    **UPDATE FOR loadImage function**

    func loadImage(cell: UITableViewCell, photoURL: NSURL?) {
    DispatchQueue.global(qos: .userInitiated).async {
    guard let imageURL = photoURL, let imageData = NSData(contentsOf: imageURL as URL) else {
    return
    }
    DispatchQueue.main.async {
    cell.imageView?.image = UIImage(data: imageData as Data)
    cell.setNeedsLayout()
    }
    }
    }

  • Sharkes Monken

    Enjoyed a single bit of it. Great article

  • Florian Marcu

    This is an excellent introduction to MVVM. Building on this, I’ve put up an article on a more concrete app – the MVVM architecture of a news reader app in Swift 3, which you find at http://iosapptemplates.com/blog/ios-programming/designing-news-reader-ios-app-swift

Type your search keyword, and press enter to search