Swift: Using MVVM To Work With Optionals

I’ve recently started using the Model-View-ViewModel pattern a lot more to structure my iOS application code. While MVVM is not necessary in all cases, I’ve found it to be especially useful when writing iOS applications in Swift aka working with Optionals.

I’ll use my demo SeinfeldQuotes app as an illustration of this. The App has a screen for displaying all Seinfeld quotes, and one for adding a new quote:

SeinfeldQuotesApp    Create Quote App

The Model

The Quote Model for the SeinfeldQuotes app looks like this:

class Quote {
   
    let content: String
    let scene: String
    
    init(content: String, scene: String) {
        self.content = content
        self.scene = scene
    }
    
}

I specifically chose to NOT make my Quote content and scene properties optional, because it’s not really a Quote if it doesn’t have content or the Seinfeld scene it was from. I also chose to make the quote fields constants, since quotes don’t change.

If I did choose to make these fields optional, I would have to go through the pain of unwrapping the multiple optionals when displaying the quote on the Seinfeld Quotes page and throughout the application. How should the quote be displayed if the content is missing? Should it even be displayed? Making fields optional adds an additional level of complexity that I like to avoid if possible.

The ViewModel

Notice that the Create Quote screen does have an optional state for each field – the page is initialized with nil values for both the quote content and the quote scene.

Create Quote App

This is where the ViewModel comes in handy – it can keep track of the quote fields as optional variables, as well as some additional information we need for configuring the display for the Create Quote screen (placeholder text in this case):

class QuoteViewModel {
    
    var quoteContent: String?
    var quoteScene: String?
    
    let quoteContentPlaceholder = "Quote Content"
    let quoteScenePlaceholder = "Scene Description"
    
    init(quoteContent: String? = nil, quoteScene: String? = nil) {
        self.quoteContent = quoteContent
        self.quoteContent = quoteScene
    }
    
    func createQuote() -> Quote? {
        switch (quoteContent, quoteScene) {
        case let (.Some(quoteContent), .Some(quoteScene)):
            return Quote(content: quoteContent, scene: quoteScene)
        default:
            return nil
        }
    }
}

The ViewModel can also have validation logic to make sure all the quote fields are present for the quote to be created as demonstrated in the createQuote function above.

The ViewController

Now, I can use the viewModel throughout my CreateQuoteTableViewController:

import UIKit

class CreateQuoteTableViewController: UITableViewController {

    private let quoteViewModel = QuoteViewModel()
    
    private let textCellIdentifier = "textInputCell"
    private let numberOfFields = 2
    
    private enum QuoteField: Int {
        case Content, Scene
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        navigationController?.hidesBarsOnSwipe = false
    }

    // MARK: Actions
    
    @IBAction func onSaveTap(sender: UIBarButtonItem) {
        if let quote = quoteViewModel.createQuote() {
            // SAVE quote in your data store
            navigationController?.popViewControllerAnimated(true)
        } else {
            let alertController = UIAlertController(title: "All fields required", message: "Please make sure all fields are filled in to add the quote!", preferredStyle: .Alert)
            alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
            presentViewController(alertController, animated: true, completion: nil)
        }
    }
    
    // MARK: Table View Delegate
    
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfFields
    }
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier) as TextInputTableViewCell
        
        if let quoteField = QuoteField.fromRaw(indexPath.row) {
            
            switch quoteField {
            case .Content:
                cell.configure(text: quoteViewModel.quoteContent,
                    placeholder: quoteViewModel.quoteContentPlaceholder,
                    textFieldChangedHandler: {[weak self] (newText) in
                        if let strongSelf = self {
                            strongSelf.quoteViewModel.quoteContent = newText
                        }
                })
            case .Scene:
                cell.configure(text: quoteViewModel.quoteScene,
                    placeholder: quoteViewModel.quoteScenePlaceholder,
                    textFieldChangedHandler: {[weak self] (newText) in
                        if let strongSelf = self {
                            strongSelf.quoteViewModel.quoteScene = newText
                        }
                })
            }
        }
        
        return cell
    }
}

Note that only when the user clicks Save, does the Quote object actually get created (if the fields are filled in of course!). Instead, the quoteViewModel object is manipulated as the user fills in the Quote fields.

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.

  • Andrew Bancroft

    I think I kinda like your idea of using the ViewModel as the “thing” that does the validation and the handling of the optionals – it makes sense especially in data entry scenarios where all the text boxes start out with nil.

    The separation of concerns makes your view controller much nicer than it would be otherwise. If the validation logic is super complex, perhaps that could even be factored out to a validation class of some kind. But yeah – I think I like your approach!

    I’ll study the code in greater detail when I get to a bigger screen. Thanks for sharing the insight!

    • You can also see the source code here: https://github.com/NatashaTheRobot/SeinfeldQuotes

      • I’ve noticed in your ViewModel, that you have a typo:

        init(quoteContent: String? = nil, quoteScene: String? = nil) {
        self.quoteContent = quoteContent
        self.quoteContent = quoteScene
        }

        The last line should be self.quoteScene = quoteScene

    • Yes, Natasha, excellent article! 😀

      Andrew, that is precisely why a ViewModel (VM) or Presentation-Model (PM) is used in MVVM and MVP patterns. Not only does it reinforce lightweight view controllers, it allows simpler and more specific tests throughout your model states. More explanation can be found here: http://www.objc.io/issue-13/mvvm.html

  • Mark Patterson

    That trick of using a switch with a tuple is a nice way to avoid the leaning tower of if-let. Good one. I hope Swift gets a nicer syntax for multiple unwrappings.

    • I actually like the unwrapping multiple optionals syntax – it reminds me to think of all the possible combinations!

      • lozandier

        Was Optional Chaining impossible for this particular class? It avoids the if-let pyramid of doom in ways that I’ve haven’t had to nest if-let yet.

        • Using switch statements gets rid of the nested if-let layers. Can you give an example of how optional chaining would be useful in this case?

          • lozandier

            That’s what I understood from your use of switch case. I was just curious if quoteViewModel had any chance of being chained to self/strongself before the use of if-let in your particular example…

          • Joshua Worby

            I think another option in this case would be to use guard. IMO it’s a more obvious what you’re protecting against than a switch statement.

            For example,

            guard let content = quoteContent, let scene = quoteScene else {
            return nil
            }
            return Quote(content: quoteContent, scene: quoteScene)

  • Thank you for this post 🙂

  • Nick H

    Thanks for writing this article. It’s a good intro to the MVVM pattern. I do have a few questions though. In general, how does one determine what should be in the ViewModel, and what should be in the View? I’m assuming the ViewController is counting as the “View” for this case.

    Much of what is in the ViewController seems specific to the view, like the textCellIdentifier or the enum for which tableViewCell is being referred to and that makes sense.

    The placeholder text being put in the ViewModel is what I am most confused by, why is that not in the ViewController. I just want to understand where the line is drawn between ViewModel and View (or ViewController, in this case).

    Great article, thanks for helping out the Swift community.

    • The View in this case is the QuoteTableViewCell. You can think of the ViewModel as the View Data Layer – how should the stuff behind your model be displayed in the view? The ViewController is the in-between. So the placeholder text, for example, is view data – it has to do with how the information that the model needs will be displayed to the user. Hope that helps. I recommend trying it out and just seeing how it works for you. I’ll try to write a more complex MVVM example blog post, which should make this more clear. But yes, there is some gray area. I recommend just trying it out and seeing what makes sense to you.

    • Bo83

      My guidelines from my .Net days was always this; business logic goes into the ViewModel classes and UI Logic goes into the view controller classes. A good coding guard rail I used was to never import the System.Windows.Forms namespace into my ViewModel classes.

      The equivalent in the iOS world would be to never import UIKit into your ViewController classes. Just as in Natasha’s example, when you look at your ViewController classes you should only see logic that deals with manipulating the view and other UI controls – never the business logic.

      And vice versa for the ViewModel, you should only see code associated with the business logic and never any code pertaining to visual UI controls.

      Thanks for this article Natasha, I always wondered why I never saw more iOS tutorials across the internet that emphasized good app architecture. Not a biggie for quick and dirty apps but absolutely necessary for larger apps.

      • Isuru Nanayakkara

        Here is a list of resources I’m compiling on good iOS app architecture – https://coderwall.com/p/virp-q. I need to sort it though. Btw thanks for the brief explanation to MVVM. I’ve been interested in learning more since of late. Can you please explain where the networking code should go in MVVM?

        • Bo83

          Hey Isuru, thanks for the list of sites, those seem like some good resources – can’t wait to go thru them and see what good tips I can use.

          As for networking code I put all of those into re-usable utility classes that are consumed by the business logic layer. I’m pretty strict on trying to keep my business logic exactly that – business logic. For example, a bank makes money by transferring money around between banks and corporations. So we would expect their business logic to have plenty of references to something like:

          _transferUtils.ExecuteWireTransfer(sourceAcct, destinationAcct, amount)

          but that’s all we would see, what API’s are being used to accomplish the transfer is of no concern to the business logic. The actual calls to the networking api should live within the TransferUtils class.

          I’m new to the iOS/mobile arena but from what I’ve seen there are tons of new API’s introduced which each major version (4,000 for iOS 8) and a lot get deprecated also.

          I want to shield myself away from those API changes as much as possible. Think of it this way — why should an API change require a rewrite of the business logic? The only thing that should prompt a re-write of the business logic is if the company changes the way they do business – right.

          Same question can be applied for presentation logic. Mobile interfaces change often due to user feedback and incremental realization of better UI flows. We’re not changing how we do business just how we display info to the user.

          So UI overhauls shouldn’t constitute a rewrite of your business logic either. You’ll undoubtedly have to make minor changes here and there to support new UI elements but there definitely shouldn’t be any major changes to the core logic that dictates the business rules.

          So my mode of attack is to identify those API’s that I reuse over and over, like NSUrlSession, and place those API calls into a utility class that I can reuse throughout my app. That way if I need to update those API’s (like replacing NSUrlConnection with NSUrlSession) then I only have to update my utility class and thats it.

          I don’t have to go through my entire app looking for every place that NSUrlConnection is used and then retest that functionality. It’s a small level of abstraction that provides great maintenance benefits.

          Same can be done for presentation logic. I have an extension method for UIViewController called ShowAlert(). It’s responsible for displaying alerts via the new UIAlertController. So in all my view controllers you only see calls to ShowAlert() and never anything regarding UIAlertController or UIAlertAction.

          Key thing to note is that these are small levels of abstractions i.e. a separate class, an extension method – things like that. You don’t want to over engineer and go OO crazy.

          So many people do what I like to call – “stream of consciousness coding”. I.e. if they’re in the ViewController and need to make a network call they just code it. Instead of stopping for a few seconds and asking themselves – “do I use this often?” — “what’s the best place for this code to live?”. Its basically just disciplining yourself to use good code organization.

          • Isuru Nanayakkara

            Thanks for the detailed reply 🙂 I already put network, database API functions in separate classes. I’m just wondering where I should be calling them when it comes to MVVM. So I guess network/database requests, user input validation stuff like that goes in the ViewModel?

          • Bo83

            yep, that’s it. The storyboard views and view controller logic only exists to feed data into the business logic layer (BLL) and to display data received from the BLL. Your business logic should be able to fully execute and perform its duties without any assistance from the UI.

          • Isuru Nanayakkara

            Got it! Thanks again for explaining everything. Do you have a twitter by any chance?

          • Bo83

            afraid not, I probably should get with the times and get one but I’ve found twitter and facebook gives you a direct line to peoples daily drama and I don’t want to deal with that everyday. I’ll probably set one up though to start using for industry related points.

          • Isuru Nanayakkara

            Oh okay. Yeah you should. That’s what I do too. I only follow people in my industry and blogs/sites on Twitter. And I only share stuff related to SE too. It’s been beneficial for me personally quite a few times. Add me up if you ever come around to make one 🙂 – @IJNanayakkara.

          • Bo83

            finally made the dive into the twitter world, thanks for the push – @theswiftdude1

          • Isuru Nanayakkara

            Awesome! I just followed you. See you around 🙂

          • @Bo83:disqus thanks for the in-depth explanation!

            @isurunanayakkara:disqus – I usually put validation logic in the ViewModel. By validation, I mean the ViewModel function returns a Bool as to whether all required fields are filled out, for example.

            In the ViewController, I use the ViewModel to check whether the validation passed, and if so, make the call to the API utility function. The reason I do this part in the ViewController, is because the API function usually has a success / failure handler block, which then handles the UI (alert if an error, re-direct to another screen if success).

          • Isuru Nanayakkara

            Hello again 🙂 I have a new question I hope you could answer. If you use Core Data in your app, the core data classes become the Model, right? Where do you put the helper methods for each entity? For example say there’s a class called Person with 2 properties, firstName and lastName. I need to create a method called getFullName() which concatenates those two property values and return the person’s full name. Where should I put that getFullName() method? I have heard people voting against putting custom methods inside NSManagedObject subclasses. What kind of approach do you take? Thanks.

          • Bo83

            waddup dude, for Swift I would make an extension for the person class like follows:

            extension Person
            {
            var FullName : String
            {
            return “(firstName) (lastName)”
            }
            }

            Hopefully one day Swift will implement the partial keyword like C# does. The partial keyword was designed primarily to accommodate auto-generated classes. It allows you to divide up a class over different files so that your static methods and properties reside in different files and are persisted while allowing the auto-generated files to be repeatedly overwritten. But using extensions is a great solution also.

          • Isuru Nanayakkara

            Great! Thank you. I was thinking of putting the extensions in a separate file. At least until I get my object model stable because I tend to generate NSManagedObject subclasses all the time and I might forget to copy the extension methods before regenerating the class file.

  • nsomar

    Good article direct to the point as always

  • Pingback: Swift: Using MVVM with Optionals [iOS developer:tips];()

  • Great example. I’d suggest considering a constant struct instead of a class with constant properties for your model though. That way you can safely pass it around threads.

  • konrad77

    1. You’re assigning quoteContent twice in QuoteViewModel. 2. I wouldn’t clutter my models with logic, instead either create an extension or let another class handle the logic.

  • Pingback: Swift 2.0: Protocol-Oriented MVVM()

  • Joao Paulo

    Thank you for your post, it has helped me a lot in understanding MVVM implementation. I just did not understand one part. Maybe it is a bit off-topic, but I could not really get the textFieldChangeHandler parameter inside cellForRowAtIndexPath. What is [weak self] or this closure doing? Once again, thanks a lot.

  • Brian McCall

    On the MVVM model, what are the pros/cons of using “class” vs “struct”? I can see that we can achieve using both and Apple has recommended to use struct whenever possible.