In the last few lessons, we've managed to create a Weather Manager object which is able to perform the 1
networking that fetches the live data from OpenWeather Map, 2
and then we're able to pass the weather into an actual Swift object which we can access in a Swifty 3
format like this. 4
In this lesson, I want to focus on getting hold of our weather conditions because we need to be able 5
to update this image view with a different image from the system's 6
SF icons, so that it represents the condition of the weather. 7
Now, if we take a look at the API doss for OpenWeather, you can see that they've got this section on 8
list of condition code. And this section here links to all of the condition codes that they use, and that 9
refers to the ID property in the data that we get back. 10
What do these IDs actually correspond to? 11
Well, they're a way of encoding different weather conditions. 12
So, for example, everything from 200 to 232, encode some sort of thunderstorm, and there's 13
apparently different types of thunderstorms which I didn't really know about, 14
like a ragged thunderstorm. I don't want to be in one of those. 15
Now, we know that we can get hold of the ID which is the ID of the weather condition and we can match 16
it against these values to see what type of image we should show the user. 17
So let's go ahead and do that. Instead of getting hold of the description which we're not actually gonna 18
use, 19
instead, I'm going to change this property to "id" and the "id" is an integer data type. And I can do 20
this because the "id" is actually nested inside at the same level as the description. 21
So changing that over from the description to the "id" or you can if you want to just simply added on 22
as an additional property if you plan on using the description at some later stage. But they both live 23
within this Weather struct which is an array of weather conditions that we're getting back which comes 24
from the entire WeatherData. 25
So following it down, this is the first property which goes into an array, which then has an object with 26
a property code "id." 27
So quite convoluted, but eventually, we should be able to get a hold of this number. 28
Let's go ahead and try to print that in our WeatherManager just to make sure that it's actually working. 29
So let's see what it's like in Bali at the moment. And the weather condition code I'm getting back is 30
803. 31
And if I check against this table 803 is broken clouds, 51 to 84 percent. 32
Interesting. 33
So in this case, I would probably just show a cloud in my app right here. 34
So this is the perfect opportunity to utilize what you've learned about Swift switch statements a few 35
modules back. 36
So I'm going to set this to you as a challenge. Given that we have this ID which I'll call 37
let id = decodedData.weather [0].id, 38
I want you to create a function down here that we'll call 39
getConditionName, and it takes the input in the format of the weatherId which is going to be an integer, 40
and then inside this function, we're going to return a String. And that string will depend on the Weather 41
ID. 42
So we're going to call this getConditionName and pass in the id right here that we get back, 43
and then inside this method was somehow going to use a switch statement to output a string, and that string 44
should match the name of one of these symbols. 45
So, for example, if we were getting clouds, then maybe we would simply return the word "cloud" which would 46
match with this image's name. 47
And if we got, say, rain then maybe we would put cloud.rain to get this symbol. Because, eventually, 48
what we're going to do is we're going to be using that condition name to change this image view here. 49
So if we got cloud.rain as the condition name, that's what we would see. If we got just a cloud, 50
then we would get this image. If we got sun.max, then we would get this image. 51
So feel free to pick and choose whichever icon takes your fancy as long as they more or less match the 52
condition name that we're getting back from Open Weather Maps table. 53
And then when you get this condition name back, I want you to go ahead and print it, so that when you 54
run the app and you put in the name of a location, say in Paris, and you go ahead and get the weather 55
for it, you should be able to get a name for a SF symbol that matches the weather condition of that 56
location. 57
Now, if you already know all about the Swift switch statements and you don't want to complete this challenge, 58
then you can also head over to the README file and you'll find the switch statement already written 59
for you. But I recommend that more practice is always good. 60
So using a Switch statement, try and print out the name of an icon that matches the condition ID from 61
OpenWeather Map. 62
I'm going to leave it up to you to pause the video and complete the challenge if you want to. All right. 63
So here's our Switch statement. And it looks at the weatherID that we get passed over and takes a 64
look at its value, and tries to match it against these cases, and these cases I've put in as ranges. 65
So the range between 200 and 232 in the weather condition codes matches a thunderstorm. 66
So out of all of these pictures of thunderstorms, I think the cloud.bolt looks quite nice. 67
So I've decided to return cloud.bolt, and I've done basically the same thing to match all of these 68
different conditions. 69
And in the default condition where none of these cases match, then I'm just gonna return cloud as the 70
default option. 71
Now, if you are at all confused about Switch statements or the range operator, then be sure to head back 72
to some of those Swift Deep Dives where we talked about those things in more detail. And that's the solution 73
to the challenge. But now you might be noticing that this file is getting a little bit messy and we're 74
getting to the point where we kind of need to group some data in a custom data type. And that is, of course, 75
the role of the data model. 76
So let's do that now. 77
Let's reorganize our code in accordance with the MVC design pattern. 78
This means that we'll take some functionality out of the WeatherManager and put it into a separate 79
file. 80
That way, we'll have shorter and simpler files that are easier to understand. If I want to create a custom 81
weather data model which is able to figure out the condition name based on the condition ID, then I 82
would need to go into my Model folder and create a New File which I'm going to call the WeatherModel, 83
and I'm gonna use this file to model what a weather object should look like. 84
Let's create it as a struct and it's gonna be called a WeatherModel and it's gonna have a number of 85
properties. 86
So we definitely need to have a conditionId property which is an Int. 87
We also need to have a city name property which is gonna be a String. 88
And finally, we also need a temperature property which is gonna be a Double. 89
So now I can go ahead and move this functionality of figuring out what the condition name should be 90
based on the condition code or the weatherId. 91
This is very much within the realm of the weather object. 92
So let's go ahead and paste that in here. 93
Now, back inside our Weather Manager. Instead of having all these disparate pieces of information, I can 94
create my ID as my decodedData weatherId. I can create my temperature or temp as the 95
decodedData.main.temp. 96
And finally, I'm gonna create my city name or I'm just gonna call it name for short 97
from the decodedData.name property. 98
So, now that I've got all the properties that I want out of my weather data, I can create myself a weather 99
object from my new WeatherModel. 100
So when we initialize it, we have provide the conditionId which is the ID, the cityName which is 101
name, and the temperature which is temp. 102
Now, if I wanted to get a hold of the ConditionName, then I can simply write weather.getConditionName 103
and I have to pass in the ID. But wouldn't it be nice if I could just have a property in my weather 104
object that's called a condition name and it manages to figure out what that should be. 105
Instead of getting my weather manager to call the method getConditionName, in order to get the ID. 106
This is a good opportunity to show you a cool thing that we can do in Swift which is called a computed 107
property. 108
So we've got all three properties here which are actually called stored properties because all they 109
do is they just store pieces of data. 110
But I can also create a computed property. 111
So I'm going to create it using a var keyword and I'm going to call it the conditionName, and it's going 112
to have a data type of String, and then I'm going to open up a set of parentheses. And inside the set 113
of parentheses, I'm expected to return or output what the value for the condition name should be. 114
That would require me to work out the condition name which, luckily, I've already got down here in the 115
form of my Switch statement. 116
So let's paste that in here and we can use the conditionId property value to switch, and then check 117
what condition it is to return this string which is going to be equal to the conditionName. 118
So, now I've got a computed property because this property condition name is going to work hard 119
its value based on the code inside these curly braces. 120
What this allows me to do is if I want to get hold of the weather condition, all I would have to do is 121
say weather.conditionName and I can use it just like any other property. 122
And if you run your app right now, you'll see it works perfectly 123
just like before. 124
But our code is now a lot better after the refactoring and it's a lot more succinct and easier to understand. 125
So what's a general format for computed properties in Swift? 126
Let's go over the syntax for computed properties again. In order to create a computed property, 127
it always has to be a var because the value is always going to change. It's going to be based on the 128
computation. 129
And then we give it a name, 130
so let's call it aProperty. And then we have to give it a data type, 131
so let's say I want it to be an integer. 132
Now, in between the curly braces, I have to provide an output that is going to be set as the value of 133
this property. 134
So let's say that I wanted to calculate, I don't know, 2 + 5, 135
So this is the computation 136
and that means aProperty is going to be equal to the result of this computation which is going to be 137
7. 138
That's all computed property in Swift. 139
And as practice and as a challenge, I want you to figure out how we can get hold of the temperature as 140
a string with only one decimal place. 141
So you've done this before using the string initializer, 142
but I want you to turn that into a computed property now, and it should be called temperatureString. 143
And if you manage to successfully solve the challenge, then you should be able to print 144
weather.temperatureString. And when you run the app and check the weather, then you should get the temperature 145
back in a string format with only a single number after the decimal place. 146
So pause the video and see if you can complete this challenge. 147
All right. 148
So we've got a temperatureString computed property here. 149
And remember, we always have to provide a data type for the computed property, and then we open a set 150
of curly braces and actually work out what it should be. 151
So in this case, I'm going to return a String with the format of a single decimal place, 152
so thats's "%.1f" and then I'm gonna pass in my temperature which is this Double right 153
here as the property that's going to be formatted to this particular format. And now when you run your 154
app, you should be able to see that whatever temperature you get back will be printed with only one decimal 155
place. And this temperature string now has the data type of a String ready for us to put into our temperature 156
label. 157
So in the next lesson, we're going to tie it all together and get our weather app working with all of 158
these different components together. For all of that and more, I'll see you there.