This workshop will be retired on May 31, 2020.
Implementing MVVM11:39 with Amit Bijlani
Refactoring the Stormy app from the Networking in Swift course to implement the MVVM design pattern.
I'm going to take the stormy app from the networking with swift course. 0:00 We'll take a look at the drawbacks of the current implementation and 0:05 how we can modify it to implement.MVVM. 0:08 So here I have the stormy project from the networking and swift course. 0:13 If you want the starter files look at the teacher notes 0:17 to download the starter files. 0:20 So right off the bat, I just wanna discuss the MVC design pattern or 0:23 the Model-View-Controller design pattern. 0:27 You'll notice that this application follows the MVC design pattern. 0:31 The Main.storyboard is the view. 0:36 The View Controller is, of course, a controller and 0:39 if we expand the Weather Model, you will see that the current weather is our Model. 0:42 So here we have the Model, the View, and the Controller. 0:48 We have all those three layers that make up the MVC design pattern. 0:52 So before we go any further, let's take a look at our ViewController and 0:58 take stock of all of the things that it does. 1:03 Right off the bat we can see that we are extending our 1:06 Model within our ViewController. 1:09 Now why are we extending the Model? 1:12 Well if you can see, we've created three properties and 1:14 these three properties are essentially formatting, the original data for 1:18 display because the original data is either an integer or double. 1:23 And then it needs to be formatted as a string or made pretty enough so 1:29 that it can be displayed by the View. 1:33 Now, this is the perfect candidate for a ViewModel. 1:36 Before we continue let's go down and 1:41 look at all the other pieces of code that we have here. 1:44 Here we have a bunch of IB outlets which is fine. 1:47 Our Controller is meant to control the View. 1:50 So these are just IB outlet store view. 1:54 We have lazy properties and constants which are related to our network calls. 1:56 The viewDidLoad we are making a network call. 2:02 This is the fetchCurrentWeather method. 2:05 And there's our fetchCurrentMethod which is essentially making a network call. 2:07 Now, if we follow the Single Responsibility Principle, 2:12 we don't want to be making a network call right here. 2:16 Our Controller should essentially just be responsible for 2:20 talking to the view layer and though a Model layer and 2:24 it should not really be making the network calls. 2:29 This can be resolved using protocol oriented programming 2:32 which will cover either in a separate workshop or course. 2:36 Let's move forward. 2:40 So here is our display methods. 2:42 I don't really like the word display. 2:45 I would rather call this configured, but this displays fine too. 2:47 So the display method is essentially configuring the View. 2:51 It's essentially assigning values to the labels taken 2:55 from the extension that we created from the Model. 2:59 Finally you have the show alert method which shows an alert in case something 3:02 goes wrong while fetching the results from the network. 3:07 And then you have couple of IB actions this is an IB action related to 3:10 the refresh button and this is the refresh animation. 3:15 So these three things are related to controlling the View which is fine, 3:20 that's what our Controller is meant to do. 3:24 So the only things that are out of place here are the extension 3:28 of the Model and the network request. 3:33 So since we're discussing MVVM which is Model View View Model, 3:37 let's talk about how we can create that ViewModel layer. 3:44 So we'll go over here and create a new file, so 3:48 we'll select new file and we'll create a new Swift file. 3:51 So I'll call this CurrentWeatherViewModel. 3:58 So this will be a struct, I'll discuss further why this should be a struct. 4:08 Essentially a struct is a value type and 4:17 since our model is also a value type it makes a lot of sense for 4:19 us to have a struct as a value type where we don't have any other references. 4:24 And we just keep copies of the data that can be easily created and 4:29 the best thing about creating value types is that they are easy to test. 4:34 And this is something we're going to cover in the next video and 4:39 how we can test our view models. 4:41 So I'll go back here and I'll copy these three properties and 4:44 I'll remove this extension. 4:49 I don't have any line numbers. 4:55 So let's go ahead and add line numbers here. 4:57 It's just driving me crazy, not seeing any line numbers there. 5:00 So going back to our view model here I've added those three properties. 5:05 Now we're missing something, right? 5:11 We're missing where this data is coming from. 5:14 So we'll create a let, and 5:18 say Let weather be of type Currentweather. 5:22 And now we can refer to this constant that we created weather. 5:29 And then we can create a designated initializer that takes 5:41 in the current weather and assigns it. 5:46 To our constant property. 5:53 So we'll say self.weather = currentWeather. 5:56 Perfect. 6:01 So I messed up here sorry, this should be a percentageValue. 6:03 This should be here weather.humidity and 6:08 weather.precipitationProbability, so there. 6:13 Thank you compiler. 6:20 And the wow, this is not giving us any 6:21 more compiler errors so we can move back to our view controller and 6:27 of course we have a few errors here because there is no. 6:32 There is no ViewModel declared here. 6:38 So let's find out who is calling our display method. 6:40 We can right click on it and select find call hierarchy and 6:46 we can see that the fetch current weather method is calling the display method. 6:50 That's great. 6:56 So there's only one other method that is calling the display method. 6:57 Now we know that there is only one of the place where this is being called, 7:02 we can easily reach factor this. 7:06 So what we'll do is we will create an instance of current whether ViewModel. 7:10 And we'll provide it the current weather, so 7:19 since this is swift three we have to provide the labels so 7:23 we'll see current weather and here instead of whether we should say viewModel. 7:27 And this will be of type CurrentWeather. 7:36 Current weather ViewModel. 7:40 Okay, so now instead of 7:42 getting it directly from the Model, we will get it from the viewModel. 7:47 Now a couple of issues here. 7:51 Let's revisit some of our constraints, or our rules regarding viewModels. 7:55 Rule number one is that the viewModel is 8:02 the only layer that talks to the Model. 8:07 And the viewModel can format data for display. 8:15 So if the viewModel is the only layer that talks to the Model 8:22 then we can no longer access the Model from the controller. 8:26 So the summary and icon cannot really belong here. 8:30 So what do we do? Well let's go back to our viewModel and 8:35 add those two properties as well, so 8:40 we'll say var summary String. 8:45 And then we'll just simply return it from a weather.summary. 8:49 I'll say var icon is your image,whoops. 8:55 So it doesn't recognize because we have to import UIKit, there you go. 9:06 And now we'll say return weather.icon. 9:15 So of course we're simply returning the summary in icon here, but 9:21 in case there is no data we could display a default icon for display. 9:26 In case there is no summary we could display some default text or 9:32 implement our own business logic based on whether it's sunny or 9:37 cloudy we can display a clever little message. 9:40 So this is the whole advantage of having a view model where we 9:44 don't have to clutter a controller or we don't have to clutter our Model and 9:48 we can play around with adding business logic inside our viewModel so 9:52 that we can format our data for display. 9:57 So I would encourage you to be creative here, and experiment how 10:00 you can come up with creative solutions to displaying better data for display. 10:05 So going back to our controller, 10:11 now we can change this to viewModel and this as well. 10:13 So as you can see it did not take us a whole lot to refactor this controller, 10:19 take out the model extension and create a view model from it. 10:25 So let's run our app. 10:31 And hopefully it should still display. 10:34 So this still works if I hit refresh that works as well. 10:36 So by moving the whole block of code 10:42 that extended our model we're transferring the responsibility of formatting a text 10:45 from my controller to our viewModel which is of course one of its functions. 10:50 Now example was simple and straightforward. 10:56 Maybe the code handed to you is not so simple. 10:59 But I'm certain if you apply the constraints we defined in 11:02 the previous video, you should be able to easily apply the MVVM design pattern. 11:04 Let's revisit our list of constraints and see if we actually stuck to them. 11:10 Our controller now interacts with only the view and viewModel. 11:14 Other than the viewModel, nothing else interacts with our Model. 11:18 Our View only interacts with the Controller. 11:22 Remember, we talked about the viewModel being a value type. 11:26 One of the key benefits to creating a viewModel 11:30 is to make our code more testable. 11:32 So, stay tuned for the next video where we talk about unit testing. 11:35
You need to sign up for Treehouse in order to download course files.Sign up