If you’re not sure how the various pieces of the Model-View-ViewModel pattern fit together, then this chapter is certainly going to help. In this chapter, we put the DayViewViewModel
we created in the previous chapter to work. This means we need to refactor the day view controller and the root view controller.
The first step we need to take is replacing the now
property of the day view controller with an instance of the DayViewViewModel
struct. Only the name and the type of the property change. We can leave the didSet
property observer untouched.
DayViewController.swift
1
var
viewModel
:
DayViewViewModel
?
{
2
didSet
{
3
updateView
()
4
}
5
}
With the now
property removed from the DayViewController
class, we need to update the root view controller. It no longer passes the WeatherData
instance to the day view controller. Instead, the root view controller instantiates an instance of the DayViewViewModel
using the WeatherData
instance and sets the viewModel
property of the day view controller.
Open RootViewController.swift and navigate to the fetchWeatherData()
method. In the completion handler of the weatherDataForLocation(latitude:longitude:completion:)
method, we create an instance of the DayViewViewModel
struct and assign it to the viewModel
property of the day view controller.
RootViewController.swift
1
private
func
fetchWeatherData
()
{
2
...
3
4
dataManager
.
weatherDataForLocation
(
latitude
:
latitude
,
longitude
\
5
:
longitude
)
{
(
response
,
error
)
in
6
if
let
error
=
error
{
7
print
(
error
)
8
}
else
if
let
response
=
response
{
9
// Configure Day View Controller
10
self
.
dayViewController
.
viewModel
=
DayViewViewModel
(
weat
\
11
herData
:
response
)
12
13
// Configure Week View Controller
14
self
.
weekViewController
.
week
=
response
.
dailyData
15
}
16
}
17
}
This confirms what we discussed in the previous chapter. The day view controller no longer has direct access to the WeatherData
instance. It can only access the model indirectly through the view model.
The last piece of the puzzle is updating the updateWeatherDataContainer(withWeatherData:)
method of the DayViewController
class. But first, we’re going to rename the method to updateWeatherDataContainer(withViewModel:)
. That makes more sense.
DayViewController.swift
1
private
func
updateWeatherDataContainer
(
withViewModel
viewModel
:
Day
\
2
ViewViewModel
)
{
3
...
4
}
This also means we need to update the updateView()
method of the DayViewController
class. Notice that I’ve also replaced any references to the now
property with references to the viewModel
property.
DayViewController.swift
1
private
func
updateView
()
{
2
activityIndicatorView
.
stopAnimating
()
3
4
if
let
viewModel
=
viewModel
{
5
updateWeatherDataContainer
(
withViewModel
:
viewModel
)
6
7
}
else
{
8
...
9
}
10
}
The implementation of updateWeatherDataContainer(withViewModel:)
becomes much shorter. Instead of using the raw values of the model, we simply ask the view model for the data the view controller needs to display in its view.
DayViewController.swift
1
private
func
updateWeatherDataContainer
(
withViewModel
viewModel
:
Day
\
2
ViewViewModel
)
{
3
weatherDataContainer
.
isHidden
=
false
4
5
dateLabel
.
text
=
viewModel
.
date
6
timeLabel
.
text
=
viewModel
.
time
7
iconImageView
.
image
=
viewModel
.
image
8
windSpeedLabel
.
text
=
viewModel
.
windSpeed
9
descriptionLabel
.
text
=
viewModel
.
summary
10
temperatureLabel
.
text
=
viewModel
.
temperature
11
}
We’re benefiting from the work we did in the previous chapter. To populate the dateLabel
, we ask the view model for its date
property, the computed property we implemented in the previous chapter. We update the timeLabel
with the value of the time
property of the view model, etc. The resulting implementation is short, clear, and focused.
I’m sure you agree that deleting code is one of the more enjoyable aspects of software development. The day view controller is now much leaner and very focused. It presents data and responds to user interaction. That’s what view controllers are designed for.
Run the application to see if everything’s still working. You’ll notice that nothing has changed. If something doesn’t look right, then you probably made a mistake in the view model.
Even though the day view controller displays a simple user interface, I hope you now understand how the Model-View-ViewModel pattern helps to keep your project’s view controllers in check. The Model-View-ViewModel pattern delegates tasks and responsibilities of the view controller to the view model.
I’ve been using the Model-View-ViewModel pattern in more complex projects and the results are pretty impressive. View controllers no longer tend to be massive and the testability of your project improves dramatically. We’re only scratching the surface, though. In the next chapter, we shift focus to the week view controller.