In the last few lessons, we wrote our networking code to fetch the Weather Data and pass the JSON response 1
from OpenWeather Map. 2
Then we created our weather model to hold on to our weather data. 3
In this lesson, we're going to tie it all together by writing the code to parse the weather information 4
back to the Weather View Controller. And to do that, 5
we're going to use delegates and protocols. 6
Speaking of protocols, sometimes more than one protocol can be combined under a single name. 7
Now, notice how we're using the Decodable protocol here. 8
If you needed to be able to encode data back into JSON format, then you could also tag on another 9
protocol which is the Encodable protocol which allows your Swift objects to be encoded into a JSON. 10
Now, in order to save people time, 11
they actually managed to create something called a Typealias that combines these two protocols, 12
and it's called Codable. 13
So when you see code out in the while that have this thing Codable that's added at the end, when you 14
click on it, you see that "Oh, it's a typealias." 15
What does that mean? 16
Well, all it is is it just combines two protocols into one and we can add them both in one go. 17
So that's something to be aware of. Now coming back to our parse JSON method, 18
once we've created our weather object from our Weather model, I want to be able to return it to the place 19
where I code parseJSON, so that way I could, for example, say, let weather = self.parseJSON. 20
And to do this, I, of course, have to provide an output to this method and it is going to be the WeatherModel 21
data type because that's what our weather is created from. 22
So how do I output this? 23
Well, I could simply just return weather right here that I've created from the data that I've parsed. 24
But what if the parsing didn't go according to plan? 25
What if we ended up with a error? 26
What if this decoding process failed? 27
Well in that case, it would actually skip all of these lines of code, and go straight to the catch block 28
and print our error. 29
Well, at this point, then we're not gonna get anything returned and our output is no longer being provided. 30
So that's why we're getting this error: Missing return in a function expected to return "Weather Model." 31
So what could we do? 32
Well, we could in the catch instance, simply return nil because we don't actually have a weather object 33
to return. 34
We didn't manage to successfully decode the data. But in order for us to be able to set something as 35
nil, 36
well, then our WeatherModel has to become an optional. 37
So, now we have this optional coming out of our parseJSON method and this is now an optional 38
WeatherModel. 39
But, of course, we want to be able to use it, so we can simply optional bind the weather object that comes 40
out of parseJSON as the output to something called weather. 41
Now, we can use this weather which is an unwrapped weather model object. What do we want to do with this 42
weather object? 43
Well, we want to send it back to the place where we need it which is the WeatherViewController. 44
We want to use the condition name to populate the conditionImageView. 45
We want to be able to just put the temperature into the temperatureLabel. 46
So how do we get it back into the WeatherViewController? Well, one way that we could do this is to create 47
a 48
weatherViewControl object from our WeatherViewController, and then inside our WeatherViewController, 49
we could create a function called didUpdateWeather and we would be able to pass in the WeatherModel object 50
as the weather. 51
And then inside here, we should be able to then print weather.temperature, and then going back to 52
our WeatherManager, then we would call weatherVC.didUpdateWeather, and then we would be able 53
to pass in this weather object as the input. 54
Now, that would work, but if we come back to what we learn in our delegates and protocols lessons, by doing 55
this, we would basically render our WeatherManager single use. It would become like a plastic cup or 56
a plastic tray. 57
We have to limit its use to this current project. But in a future project, if we needed to get weather 58
data, well, we could reuse this struct WeatherManager. And the way that we would do that is by not using 59
any specific code in it that ties it to another object, 60
say, the WeatherViewController. So we could solve this problem by simply using a delegate pattern. 61
We could say something like delegate if it exists, 62
call didUpdateWeather, and inside the didUpdateWeather, we would maybe have a input code 63
weather. And then, here we could pass in this weather object that we got back from our parseJSON. 64
So here's my challenge to you. 65
I want you to write this line of code exactly where you see it here inside the "if let" that unwraps the 66
weather object that we get back from parseJSON. And we're going to try and parse this weather object 67
back to the delegate. And the delegate is going to be our WeatherViewController. 68
So that's going to be the class where we're going to trigger this method didUpdateWeather, but we're 69
going to do it using the delegate design pattern. 70
That means that in our WeatherManager, we wouldn't need a variable code delegate, and this should have 71
the data type of WeatherManagerDelegate 72
and it will be an optional, so that whoever or whichever class or struct sets themselves as 73
the WeatherManagerDelegate would have to have the implementation for this method didUpdateWeather, 74
so that we can actually call delegate?. didUpdateWeather and pass over the weather that we have in our 75
WeatherManager 76
and it should be able to land in our WeatherViewController, and we should be able to print out the 77
temperature property of the weather. 78
Pause the video now and see if you can complete this challenge that tests your knowledge of delegates 79
and protocols. 80
All right. 81
The first thing we need to do is to create our protocol. 82
So right up here outside of the WeatherManager, 83
and remember that by convention in Swift, we create the protocol in the same file as the class that will 84
use the protocol. 85
In this case, the protocol is going to be called 86
a WeatherManagerDelegate. 87
So this is the name that we specified earlier. 88
And then the requirements are that you must be able to implement a function code didUpdateWeather. 89
And the inputs are called weather 90
and it has to be of type WeatherModel. 91
These are our requirements set out. 92
So, now we set our delegate as a optional WeatherManagerDelegate, 93
so if some class or some struct has set themselves as the delegate, then we would be able to call upon 94
the delegate and tell it to update the weather. 95
Now, remember that because we're inside a closure, our delegate has to have the keyword "self" in front 96
to make it clear that referring to the delegate in the current class which is this one right here. 97
So, now we have to go into our WeatherViewController and adopt that WeatherManagerDelegate. And as 98
soon as we do that--right now, we're not actually getting errors because we already have implemented the 99
method which is called didUpdateWeather because this is the requirement of that protocol. 100
So adopting it, we have to have this. But because it already exists, we don't get any errors. 101
But what we do have to do, which I often forget, is we do have to set this current class as the delegate. 102
So we have to say that the WeatherManager.delegate property is equal to "self." That way, 103
our WeatherManager's delegate property is not nil. And then, down here where we call delegate.didUpdateWeather, 104
this optional chaining here will actually pass through because it's not nil, and then we actually trigger 105
this didUpdateWeather and pass over this weather object. 106
So let's give it a spin to see if it works. So, now let's search for the weather in Paris again, and you can 107
see that we're getting the temperature sent over. 108
Perfect. 109
We're now adopting the delegate design pattern and our WeatherManager is now completely reusable. 110
We could use this in any other class without having to change any of the code inside and all we would 111
have to do is whatever class that needs this functionality of getting the weather data from OpenWeather Map, 112
then we would simply adopt the WeatherManagerDelegate, 113
set the class as the delegate, and then have the implementation of didUpdateWeather to be notified 114
when the weather is available from the internet. 115
This is a good time to mention that there's a couple of conventions that we use when we're adopting 116
the delegate pattern like this in Swift. 117
Notice how in the delegate methods that Apple has created, the way that they're written, they start out 118
with an underscore, and then the parameter name, and then the data type. So why is it that there's an underscore 119
there and why is it separated from the name of the tax field? 120
This is because in Swift, we can have something called a local parameter name and we can even omit the 121
parameter name when we're calling the method. To find out more about this, 122
you can head over to the next lesson 123
where we're going to do a Deep Dive on parameter names for Swift methods. 124
If you already know all about this, then feel free to skip the next lesson where we continue building 125
out our project and formatting our delegate methods.