03:25
Welcome to Mastering MVVM With Swift. In this series, you learn the ins and outs of the Model-View-ViewModel pattern. The goal is to provide you with the ingredients you need to implement the Model-View-ViewModel pattern in your own projects.
07:20
Model-View-Controller, or MVC for short, is a widely used design pattern for architecting software applications. Cocoa applications are centered around the Model-View-Controller pattern and many of Apple's frameworks make heavy use of the Model-View-Controller pattern.
04:36
In this episode, we take a closer look at the internals of the Model-View-ViewModel pattern. We explore what MVVM is and how it works.
07:46
In the remainder of this series, we refactor an application that is built with the Model-View-Controller pattern and make it adopt the Model-View-ViewModel pattern instead. This will answer two important questions. (1) What are the shortcomings of the MVC pattern? (2) How can the MVVM pattern help resolve these shortcomings?
03:43
Now that you have an idea of the ins and outs of Cloudy, I'd like to take a few minutes to highlight some of Cloudy's issues. Keep in mind that Cloudy is a small project. The problems we're going to fix with the Model-View-ViewModel pattern are less apparent, which is why I'd like to highlight them before we fix them.
02:32
Before you create your first view model, I want to revisit the internals of the Model-View-ViewModel pattern. We need to keep the following in mind. The model is owned by the view model. The controller doesn't know about and cannot access the model. The controller owns the view model and the view model doesn't know about the controller it is owned by.
08:03
In this episode, we create a view model for the day view controller. Fire up Xcode and open the starter project of this episode. We start by creating a new group, View Models, in the Weather View Controllers group. I prefer to keep the view models close to the view controllers in which they are used.
05:05
If you are not sure how the various pieces of the Model-View-ViewModel pattern fit together, then this episode will be helpful. In this episode, we put the DayViewModel struct we created in the previous episode to use. This means that we need to refactor the DayViewController and the RootViewController classes.
08:08
In this episode, we shift focus to the WeekViewController class. To adopt the Model-View-ViewModel pattern in the WeekViewController class, we start by creating a type for the view model of the week view controller. Create a new file in the View Models group and name the file WeekViewModel.swift.
06:56
The Model-View-ViewModel pattern isn't only useful for populating data-driven user interfaces. In this episode, I show you how to apply the MVVM pattern in the SettingsViewController class.
04:05
In the previous episode, I mentioned that we are repeating ourselves in the tableView(_:cellForRowAt:) method of the SettingsViewController class. We can resolve this problem with protocol-oriented programming.
04:06
The settings view controller manually configures each table view cell, using a view model. Why can't the table view cell configure itself? Can we make it autoconfigurable?
06:26
Let's apply what we learned in the previous episodes to the week view controller. The week view controller currently configures the cells of its table view. That is something we want to change. The refactoring of the week view controller involves four steps. We create a view model for each table view cell. The WeekViewModel struct generates a view model for each table view cell. We define a protocol to which the view models for the table view cells conform. The WeatherDayTableViewCell class has the ability to configure itself using a view model.
02:47
Because we moved a fair bit of logic from the view controllers of the project to the view models, we gained an important advantage, improved testability. As I mentioned earlier in this series, unit testing view controllers is known to be difficult. View models, however, are easy to test and that is the focus of the next few episodes.
07:59
In this episode, we unit test the view models of the settings view controller. We start with the SettingsTimeViewModel struct. Create a new file in the Test Cases group and select the Unit Test Case Class template.
08:17
Unit testing the DayViewModel struct isn't very different from unit testing the view models of the SettingsViewController class. The only tricky aspect is creating a DayViewModel object in a unit test.
04:07
Writing units tests for the view models of the WeekViewController class is just as easy as writing unit tests for the DayViewModel struct. We start with the unit tests for the WeekViewModel struct.
05:28
You should now have a good understanding of what the Model-View-ViewModel pattern is and how it can be used to cure some of the problems the Model-View-Controller pattern suffers from. We can do better, though. Data is currently flowing in one direction. The view controller asks its view model for data and populates the view it manages. This is fine and many projects can greatly benefit from this lightweight implementation of the Model-View-ViewModel pattern.
03:08
How do we bind the various components of the Model-View-ViewModel pattern together? That is the question we focus on in the next few episodes. It is a problem most developers new to the MVVM pattern struggle with. It isn't difficult to use the Model-View-ViewModel pattern to push data from the controller layer to the view layer. We already covered that extensively in this series. What do we need to change to automatically update the user interface if the user interacts with the application or the environment changes?
08:21
Before we use RxSwift and Combine to improve the current implementation of the Model-View-ViewModel pattern, I want to show you how you can roll your own solution using closures. I like to refer to this solution as DIY bindings or Do It Yourself bindings.
05:01
It is time to refactor the AddLocationViewController class. We start by removing any references to the Core Location framework, the import statement at the top, the geocoder property, the geocode(addressString:) method, and the processResponse(withPlacemarks:error:) method.
02:01
Before we refactor the AddLocationViewModel class, I would like to take a few minutes to explain my motivation for using RxSwift and RxCocoa. There are several reasons.
02:02
There are several options to integrate RxSwift and RxCocoa into an Xcode project. The README of the RxSwift project shows you the different possibilities. I mostly use CocoaPods and that is the approach I take in this series. If you would like to follow along with me, make sure you have CocoaPods installed. You can find more information about installing CocoaPods on the CocoaPods website.
07:04
With RxSwift and RxCocoa integrated into the project, it is time to refactor the AddLocationViewModel class. Make sure you open the workspace CocoaPods created for us in the previous episode. Open AddLocationViewModel.swift and add an import statement for RxSwift and RxCocoa at the top.
05:31
The changes we made in the previous episode broke the application. To fix what we broke, we need to update the implementation of the AddLocationViewController class. Open AddLocationViewController.swift and add an import statement for RxSwift and RxCocoa at the top.
03:51
RxSwift has been around for many years, but it isn't the only option you have. In 2019, Apple introduced Combine, a system framework that brings reactive programming to Apple's platforms. The framework provides a declarative API for processing values of time.
10:51
Before we integrate the Combine framework into the project, I want to briefly revisit the RxSwift and RxCocoa integration. RxSwift is a reactive extension for the Swift language and, as the name suggests, RxCocoa reactifies the Cocoa components you use day in day out.
04:40
We put the foundation in place in the previous episode by refactoring the AddLocationViewModel class. We complete the integration with the Combine framework in this episode by refactoring the AddLocationViewController class.
07:22
If we want to unit test the `AddLocationViewModel` class, we need the ability to stub the responses of the geocoding requests we make to Apple's location services. Only then can we write fast and reliable unit tests. Being in control of your environment is essential if your goal is creating a fast and robust test suite.
07:15
If we want to unit test the AddLocationViewModel class, we need the ability to stub the responses of the geocoding requests we make to Apple's location services. Only then can we write fast and reliable unit tests. Being in control of your environment is essential if your goal is creating a fast and robust test suite.
08:28
It is time to unit test the AddLocationViewModel class. Create a new unit test case class in the Test Cases group of the CloudyTests target and name it AddLocationViewModelTests.swift.
09:08
It is time to unit test the AddLocationViewModel class. Create a new unit test case class in the Test Cases group of the CloudyTests target and name it AddLocationViewModelTests.swift.