0 1 00:00:01,340 --> 00:00:08,660 Now, in the last lesson, we looked at how Swift tuples work. And now we're able to use it inside this 1 2 00:00:08,660 --> 00:00:16,460 "else if" statement to be able to store the first number of the calculation and also the operation of the calculation. 2 3 00:00:16,640 --> 00:00:24,930 So right at the top here, let's create a brand-new variable that is going to be our intermediate calculation. 3 4 00:00:25,010 --> 00:00:33,620 Now, as a challenge, I want you to create this as a tuple that can store a string and a number that corresponds 4 5 00:00:33,710 --> 00:00:37,350 to the first number that the user is going to calculate with, 5 6 00:00:37,640 --> 00:00:40,050 and also the operation. 6 7 00:00:40,160 --> 00:00:46,130 Now, remember, all of the things that we spoke about in the advanced Swift section and try to create this 7 8 00:00:46,130 --> 00:00:50,190 tuple so that it complies with all of the best practice. 8 9 00:00:50,200 --> 00:00:51,790 Pause the video and give it a go. 9 10 00:00:54,240 --> 00:00:54,600 All right. 10 11 00:00:54,600 --> 00:00:57,130 So here's our tuple up here. 11 12 00:00:57,360 --> 00:01:00,480 And we're not going to give it any values up here 12 13 00:01:00,480 --> 00:01:02,450 when we initialize our structure. 13 14 00:01:02,550 --> 00:01:05,470 So we're only going to specify it's data type. 14 15 00:01:05,730 --> 00:01:09,970 And remember, we specify a tuples data type with a set of parentheses. 15 16 00:01:10,290 --> 00:01:15,860 Now, the first item inside our tuple is going to be the first number. 16 17 00:01:16,110 --> 00:01:20,460 So this is going to be a Double and I'm going to call it n1. 17 18 00:01:20,550 --> 00:01:24,900 Now, the second thing we need to store in here is the calculation method. 18 19 00:01:24,930 --> 00:01:29,270 So I'll just call that calcMethod and this is going to be a String. 19 20 00:01:29,280 --> 00:01:32,460 Now, I don't actually have a value for this tuple 20 21 00:01:32,460 --> 00:01:35,860 when I initialize my CalculatorLogic structure, 21 22 00:01:36,210 --> 00:01:41,320 so I have to be able to set it to nil when I create CalculatorLogic. 22 23 00:01:41,460 --> 00:01:44,380 That means I have to turn it into an optional. 23 24 00:01:44,730 --> 00:01:51,010 And I do that by just adding a question mark to the end of the entire type, 24 25 00:01:51,060 --> 00:01:51,630 right? 25 26 00:01:51,660 --> 00:01:57,190 So in this case, the type is a Double and so the question mark goes at the end of the Double. 26 27 00:01:57,420 --> 00:02:01,210 But in this case, the type of the tuple is all of this, 27 28 00:02:01,320 --> 00:02:04,160 and so the question mark goes right at the end. 28 29 00:02:04,180 --> 00:02:07,320 Now, if instead you'd added the question mark here, 29 30 00:02:07,380 --> 00:02:11,770 then that means you can create tuples that may or may not have an n1. 30 31 00:02:11,970 --> 00:02:16,980 And if you created one here, then that means you can create a tuple that may or may not have an n1 31 32 00:02:17,070 --> 00:02:18,200 or a calcMethod. 32 33 00:02:18,360 --> 00:02:19,410 Now, that's not what we want, 33 34 00:02:19,410 --> 00:02:21,070 so we're going to delete those, too, 34 35 00:02:21,180 --> 00:02:24,900 but we're going to keep the entire tuple as an optional. 35 36 00:02:24,900 --> 00:02:32,100 Now, the final thing to consider is, remember, whenever creating global variables to start it out as a private 36 37 00:02:32,190 --> 00:02:39,500 var, that way we prevent other classes from messing withintermediateCalculation and, certainly, no other 37 38 00:02:39,510 --> 00:02:45,070 class or structure actually needs to be able to modify our intermediate calculation. 38 39 00:02:45,090 --> 00:02:50,950 It's a bit of data that we've saved right in the middle of something we're doing inside CalculatorLogic, 39 40 00:02:51,060 --> 00:02:56,220 so we have to defend it from other people accidentally changing or modifying it. 40 41 00:02:56,220 --> 00:02:59,520 So now that that's done, we can head over into this 41 42 00:02:59,520 --> 00:03:06,010 "else if" and we can set our intermediateCalculation, and I'm going to set it equal to a tuple, 42 43 00:03:06,060 --> 00:03:10,810 so a set of parentheses, and then I'm going to tap into n1. 43 44 00:03:10,950 --> 00:03:14,040 Now, I find that Xcode is not great with autosuggest 44 45 00:03:14,040 --> 00:03:15,570 when it comes to tuples, 45 46 00:03:15,570 --> 00:03:17,980 so I like to type it out just manually. 46 47 00:03:18,280 --> 00:03:23,550 Now, n1 is going to be the number that got passed over with the calculation, 47 48 00:03:23,550 --> 00:03:25,210 so that is equal to n. 48 49 00:03:25,220 --> 00:03:28,480 And then the next thing is the calcMethod. 49 50 00:03:28,530 --> 00:03:34,430 And this is simply going to be the symbol that got passed in when this calcMethod was called. 50 51 00:03:34,500 --> 00:03:39,420 So, now we have set our tuple inside this "else if." 51 52 00:03:39,450 --> 00:03:45,810 So that means when a user taps on a number, and then taps on one of the calcButtons, will pass over 52 53 00:03:45,930 --> 00:03:51,140 the number as well as the calculation method over to our CalculatorLogic. 53 54 00:03:51,360 --> 00:03:53,850 And then it's caught inside here 54 55 00:03:54,030 --> 00:04:01,020 if it was a plus sign that they pressed. aAnd we save that plus sign along with the number inside our 55 56 00:04:01,020 --> 00:04:01,570 tuple. 56 57 00:04:01,590 --> 00:04:05,060 That's called intermediateCalculation for later use. 57 58 00:04:05,070 --> 00:04:11,040 Now, at this point, Xcode, again, tells you that self is immutable because we're inside a struct and 58 59 00:04:11,040 --> 00:04:13,430 we're changing one of the properties here, 59 60 00:04:13,620 --> 00:04:16,880 so therefore, we have to mark this as mutating. 60 61 00:04:17,040 --> 00:04:22,110 So in order to succeed at this challenge, you actually have to have remembered a lot of the things that 61 62 00:04:22,110 --> 00:04:24,180 we discussed in this module. 62 63 00:04:24,210 --> 00:04:30,420 So if any of those things were at all confusing, be sure to have a look back at some of the lessons previously 63 64 00:04:30,720 --> 00:04:37,750 where we discussed access levels or structs and classes and some of the advanced Swift best practice. 64 65 00:04:37,980 --> 00:04:44,240 So, now we have to address what should happen when the user finally presses the equals button. 65 66 00:04:44,490 --> 00:04:51,720 Well, at this point, we should trigger the entire calculation and use what we saved inside the intermediate 66 67 00:04:51,720 --> 00:04:52,620 calculation, 67 68 00:04:52,650 --> 00:04:53,100 right? 68 69 00:04:53,280 --> 00:04:59,280 So let's go ahead and call another method in here which we'll call 69 70 00:04:59,340 --> 00:05:07,530 performTwoNumberCalculation. And this method is only going to have one input and that is going to be the second 70 71 00:05:07,530 --> 00:05:12,240 number that we're performing the calculation with which is, again, going to be a Double. 71 72 00:05:12,480 --> 00:05:16,200 So that number, in this case, will be, right? 72 73 00:05:16,320 --> 00:05:23,370 Because when the user has pressed the equal sign, then that means we passed in the second number that 73 74 00:05:23,370 --> 00:05:24,240 they tapped on. 74 75 00:05:24,240 --> 00:05:26,250 So let's go back to our calculator. 75 76 00:05:26,460 --> 00:05:34,200 When I press on 5 and then plus, then the calculate method gets triggered, and we fall into this "else if" 76 77 00:05:34,260 --> 00:05:41,490 bracket where we set our tuple intermediateCalculation to equal the first number that I typed which 77 78 00:05:41,490 --> 00:05:46,870 was the 5, and the calcMethod which is this plus symbol. 78 79 00:05:46,920 --> 00:05:53,180 Now, once that's done, that gets saved and stashed away ready for the next number to come in. 79 80 00:05:53,210 --> 00:05:59,060 And at this point, let's say I press on 3, and then I press equals, and I expect an answer 80 81 00:05:59,060 --> 00:06:00,070 at this point. 81 82 00:06:00,080 --> 00:06:06,800 So then the calculate function gets called again and I catch it inside this "else if" statement because 82 83 00:06:06,800 --> 00:06:09,230 the symbol was the equal sign. 83 84 00:06:09,230 --> 00:06:16,490 And then I call a function that will perform the whole calculation passing in the second number that 84 85 00:06:16,490 --> 00:06:21,680 it needed to add to the first one which happened to be 3 in my example. 85 86 00:06:21,680 --> 00:06:32,120 So let's go ahead and create this function called performTwoNumberCalculation and it expects a parameter 86 87 00:06:32,120 --> 00:06:40,480 called n2 which is going to be a Double, and it's going to return a Double as the outputs. And this 87 88 00:06:40,480 --> 00:06:49,070 functionality is internal to our calculator because it performs the second half of the calculation. 88 89 00:06:49,150 --> 00:06:54,460 And so this shouldn't be called by anybody outside this current structure. 89 90 00:06:54,550 --> 00:07:01,560 So we can mark this method as private as well to prevent from any other classes or structs from accidentally 90 91 00:07:01,570 --> 00:07:04,560 calling it because it will surely create an error. 91 92 00:07:04,690 --> 00:07:10,930 But inside this function, we're going to group together all of our intermediate calculation that we saved 92 93 00:07:10,930 --> 00:07:12,020 into our tuple. 93 94 00:07:12,040 --> 00:07:19,510 So because our tuple is an optional, then we have to unwrap it or use optional binding to check to make 94 95 00:07:19,510 --> 00:07:22,400 sure that we definitely actually have values for it. 95 96 00:07:22,600 --> 00:07:28,420 Because if the user simply pressed the equal sign right at the beginning by accident without having 96 97 00:07:28,720 --> 00:07:34,300 any operations specified or any number specified, we don't want our app to crash, 97 98 00:07:34,300 --> 00:07:34,810 right? 98 99 00:07:35,080 --> 00:07:45,400 So let's create an "if let" and let's say that if let n1 = intermediateCalculation.n1, 99 100 00:07:45,410 --> 00:07:54,700 and then we can do the optional binding calcMethod in the same line by simply adding a comma. 100 101 00:07:54,700 --> 00:08:03,760 So if let n1 = intermediateCalculation.n1, and also let operation equal 101 102 00:08:03,760 --> 00:08:11,030 intermediateCalculation.calcMethod, then and only then do we perform the code inside this block. 102 103 00:08:11,140 --> 00:08:16,740 So you can see that if I split this code into two lines, we are creating two constants. 103 104 00:08:16,780 --> 00:08:24,010 One is called n1, one is called operation. and we're creating it by optionally chaining 104 105 00:08:24,010 --> 00:08:25,090 intermediateCalculation. 105 106 00:08:25,100 --> 00:08:30,550 So we're saying if intermediate calculation is not nil, that's what that question mark says, 106 107 00:08:30,780 --> 00:08:37,200 then tap into the n1 value inside it and bind it to this thing called n1. 107 108 00:08:37,540 --> 00:08:43,680 And if intermediateCalculation is not nil, again, grab the calcMethod out of it and assign it to our 108 109 00:08:43,680 --> 00:08:44,950 operation. 109 110 00:08:44,950 --> 00:08:53,400 So now that we've got n1 and operation, both unwrapped as non-optionals, we know that they're definitely not 110 111 00:08:53,430 --> 00:08:54,230 nil, 111 112 00:08:54,410 --> 00:09:03,100 then, in this case, we can complete our calculation. So we can say that if the operation was equal to plus, 112 113 00:09:03,310 --> 00:09:11,060 then in that case, we should return as the output n1 + n2, 113 114 00:09:11,170 --> 00:09:13,790 and that is our addition functionality. 114 115 00:09:13,960 --> 00:09:21,940 So if we have a look back at our "if" statement over here, it doesn't make sense to check for plus, minus, 115 116 00:09:22,030 --> 00:09:27,920 times, multiply, divide over here if we can do it separately over here. 116 117 00:09:28,150 --> 00:09:35,530 So what I'm going to do is I'm going to cut that "else if" statement and I'm going to put it in as an "else" 117 118 00:09:35,620 --> 00:09:36,890 instead. 118 119 00:09:36,910 --> 00:09:45,460 So that means that if the symbol that was passed over was not any of these simple calculations, and it 119 120 00:09:45,460 --> 00:09:53,920 wasn't an equals, then everything else, namely, plus, minus, multiply, divide, should be caught inside here 120 121 00:09:54,760 --> 00:10:01,090 and we should create an intermediateCalculation, because everything else that remains other than these 121 122 00:10:01,090 --> 00:10:08,830 three and this button is going to be a two-number calculation. And we're going to store the actual symbol 122 123 00:10:09,100 --> 00:10:12,610 inside this calcMethod inside our tuple. 123 124 00:10:12,610 --> 00:10:20,380 So once the user presses the next number and they press equals to get the result, then we perform our 124 125 00:10:20,390 --> 00:10:23,580 two-number calculation which is a private function, 125 126 00:10:23,590 --> 00:10:28,330 so it can only be called within this current structure, not from outside, 126 127 00:10:28,540 --> 00:10:35,200 and we complete the operation by checking to see which one needed to be performed, and we return the 127 128 00:10:35,200 --> 00:10:35,810 results. 128 129 00:10:35,860 --> 00:10:40,380 So, now Xcode is telling us that this result is not handled over here. 129 130 00:10:40,540 --> 00:10:41,950 So how should we handle it? 130 131 00:10:42,010 --> 00:10:46,420 Well, of course, we're going to return it as the output of this function, 131 132 00:10:46,420 --> 00:10:46,800 right? 132 133 00:10:46,960 --> 00:10:53,860 So as a challenge, I want you to complete this part where we check for all four different operations: 133 134 00:10:54,190 --> 00:10:59,500 plus, minus, multiply, and divide, and specify what should be returned. 134 135 00:10:59,500 --> 00:11:05,760 Now, because we've got four things that we're checking. It doesn't make sense to have it as an "if" statement. 135 136 00:11:06,010 --> 00:11:12,190 So as a part of the challenge, I want you to change this to a switch statement so you can switch on the 136 137 00:11:12,190 --> 00:11:14,110 operation that needs to be performed. 137 138 00:11:14,110 --> 00:11:18,450 So pause the video and go ahead and give that ago. 138 139 00:11:18,460 --> 00:11:22,880 Okay. So let's change this "if" to a "switch" by changing the keyword. 139 140 00:11:23,000 --> 00:11:30,040 Next, let's delete all of this and all of this, so we have a blank switch statement and we're switching 140 141 00:11:30,040 --> 00:11:31,310 on the operation. 141 142 00:11:31,330 --> 00:11:33,360 So let's address some of those cases. 142 143 00:11:33,610 --> 00:11:42,790 In the case where the operation is equal to a plus sign, then we want to return n1 + n2. 143 144 00:11:46,470 --> 00:11:51,990 But in the case where the operation was a minus sign that the user wanted, 144 145 00:11:51,990 --> 00:11:53,340 then we're going to return 145 146 00:11:53,370 --> 00:11:55,580 n1 - n2. 146 147 00:11:55,620 --> 00:12:02,700 Next, if the case was a multiply, and I recommend that to get the symbol for the multiplication, you head 147 148 00:12:02,700 --> 00:12:09,060 over to the Main.storyboard and just double click on that multiply button to copy the text that's in 148 149 00:12:09,060 --> 00:12:13,660 there because unless the unicode is exactly the same, then this won't work. 149 150 00:12:13,830 --> 00:12:21,900 So, now that we've got the multiply symbol in there, we're going to go ahead and return n1 multiplied 150 151 00:12:21,930 --> 00:12:30,290 by n2. And finally, we're going to address the division which, again, I'm going to copy from over here 151 152 00:12:31,720 --> 00:12:34,210 and I'm going to paste it right here. 152 153 00:12:35,180 --> 00:12:39,210 So the last case, we're going to return n1 / n2. 153 154 00:12:39,860 --> 00:12:44,620 And as with all switch statements, you should always have a default case 154 155 00:12:44,780 --> 00:12:51,650 and this just catches out the cases where your operation that's being passed in does not match any of 155 156 00:12:51,650 --> 00:12:52,400 these. 156 157 00:12:52,490 --> 00:12:55,280 And in our case, that would be very, very weird. 157 158 00:12:55,430 --> 00:13:01,820 But we should still catch it and we should throw a fatal error because it's something that should never 158 159 00:13:01,820 --> 00:13:02,770 really happen. 159 160 00:13:02,780 --> 00:13:11,870 And in this case, we're saying that fatal error, the operation passed in does not match any of the cases. 160 161 00:13:12,170 --> 00:13:14,790 So we'll know what's happening at that point. 161 162 00:13:14,810 --> 00:13:20,450 Now, as you can see, we've had this error screaming at us for a little while now, and it's saying that we're 162 163 00:13:20,450 --> 00:13:25,050 missing a return statement in a function that's expected to return Double. 163 164 00:13:25,100 --> 00:13:28,090 Now, you can see we've got lots of return statements, right? 164 165 00:13:28,100 --> 00:13:30,430 So why are they being so hard on us? 165 166 00:13:30,650 --> 00:13:33,400 Well, it's because we've got these "if lets." 166 167 00:13:33,650 --> 00:13:37,430 And that means that there's cases when these would fail. 167 168 00:13:37,670 --> 00:13:44,600 For example, if the user opens up the app and the first thing they do is they tap on the equal sign, 168 169 00:13:44,900 --> 00:13:50,870 well, in that case, we're going to call our performTwoNumberCalculation and there might not even be 169 170 00:13:50,930 --> 00:13:52,960 an intermediateCalculation yet, 170 171 00:13:53,060 --> 00:13:53,500 right? 171 172 00:13:53,660 --> 00:13:56,090 Just because they tapped on it by accident. 172 173 00:13:56,120 --> 00:13:58,490 Well, in this case, we shouldn't crash the app, 173 174 00:13:58,490 --> 00:14:00,430 we should instead just ignore it. 174 175 00:14:00,440 --> 00:14:02,310 So how do we do that in code? 175 176 00:14:02,450 --> 00:14:08,740 Well, we can simply return nil because there is nothing to perform our two number calculation with. 176 177 00:14:09,110 --> 00:14:10,920 Now, in order to be able to return nil, 177 178 00:14:11,120 --> 00:14:15,580 we can't specify that this method only can output Doubles. 178 179 00:14:15,680 --> 00:14:21,310 It has to be able to output optional Doubles, so that we can return it as a nil. 179 180 00:14:21,320 --> 00:14:27,830 So in this case, if they accidentally tapped on the equal sign, we call performTwoNumberCalculation, 180 181 00:14:28,220 --> 00:14:29,970 this turns into nil, 181 182 00:14:30,020 --> 00:14:34,580 we return nil as the output to our calculateMethod. 182 183 00:14:34,820 --> 00:14:42,290 And over here, we catch that inside this "guard" statement which if you notice is, again, 183 184 00:14:42,290 --> 00:14:44,550 a fatalError which will crash on app. 184 185 00:14:44,750 --> 00:14:50,870 So this is a really good point to talk about what is the difference between a "guard let" and an "if let" 185 186 00:14:51,020 --> 00:14:56,240 because you'll see them all over the place in a lot of the Swift code out there in the wild. 186 187 00:14:56,330 --> 00:15:01,640 But it's really difficult for an intermediate or beginner's programmer to understand just when to 187 188 00:15:01,640 --> 00:15:03,900 use a "guard let" versus an "if let." 188 189 00:15:04,010 --> 00:15:06,130 And this is a perfect illustration. 189 190 00:15:06,470 --> 00:15:13,550 Well, in this case, when you use a "guard let," it means that you're guarding against something terrible, right? 190 191 00:15:13,580 --> 00:15:15,260 In very few cases, 191 192 00:15:15,260 --> 00:15:18,310 do you expect this "else" to be triggered? 192 193 00:15:18,620 --> 00:15:20,670 That's what a "guard let" is used. 193 194 00:15:20,720 --> 00:15:23,730 We're guarding against really bad things from happening. 194 195 00:15:23,780 --> 00:15:29,180 That should never really happen unless we had some sort of brain freeze and we completely screwed up 195 196 00:15:29,180 --> 00:15:30,440 our code. 196 197 00:15:30,440 --> 00:15:38,030 Now, if we're using an "if let" instead, then that means that we're expecting that nine times out of ten, 197 198 00:15:38,480 --> 00:15:43,660 this will not be nil and we will be able to trigger this block inside here. 198 199 00:15:43,970 --> 00:15:49,950 But we're also accepting that sometimes it might just be nil and that's fine. 199 200 00:15:49,970 --> 00:15:51,710 We don't have to do anything. 200 201 00:15:51,800 --> 00:15:54,540 We can simply ignore those cases. 201 202 00:15:54,560 --> 00:16:02,960 So, now that I've changed that "guard let" to an "if let" and only when I get a non-nil value from my calculation 202 203 00:16:03,290 --> 00:16:05,610 do I update my displayValue, 203 204 00:16:05,780 --> 00:16:12,440 then it means that if I've accidentally-- then that means that if the user has accidentally tapped on the 204 205 00:16:12,440 --> 00:16:18,410 equal sign without any prior numbers or prior operations, then we don't crash our app, 205 206 00:16:18,410 --> 00:16:20,510 instead our code just ignores it. 206 207 00:16:20,510 --> 00:16:27,170 So this is a really good illustration of why you would use "guard let" versus "if let." And I recommend that 207 208 00:16:27,200 --> 00:16:32,990 if you really want to get down to the nitty-gritties of it, try changing it around and run the app and 208 209 00:16:32,990 --> 00:16:35,300 see what happens for yourself, 209 210 00:16:35,390 --> 00:16:38,790 just so that you can get first-hand experience of what I'm saying to you. 210 211 00:16:38,810 --> 00:16:39,130 All right. 211 212 00:16:39,140 --> 00:16:44,600 So our app is pretty much done, the last thing that I'm going to change is just to make the set of "if" statements 212 213 00:16:45,020 --> 00:16:48,530 into a "switch" statement just to clean up our code. 213 214 00:17:01,550 --> 00:17:07,270 So, now we're ready to test our app and see if it works exactly the way we expect it to. 214 215 00:17:07,400 --> 00:17:18,640 So let's try 9 x 2 = 18 + 6 = 24 / 4 = 6. 215 216 00:17:18,650 --> 00:17:20,030 Clear 216 217 00:17:20,090 --> 00:17:23,110 and percentage. Everything works perfectly. 217 218 00:17:23,120 --> 00:17:30,920 Now, there's a lot more that you could do to this calculator by adding extra buttons, extra functionality, 218 219 00:17:30,920 --> 00:17:36,800 you could make it into a graphing calculator if you really wanted to or you could make it more robust 219 220 00:17:36,890 --> 00:17:39,860 and more reliable in terms of the code as well. 220 221 00:17:40,040 --> 00:17:47,090 But I hope that this has been a fun and interesting project. And along the way, we've learned about access 221 222 00:17:47,090 --> 00:17:56,360 levels, struct versus classes, mutating functions, how to use the "self" keyword, internal and external parameter 222 223 00:17:56,360 --> 00:18:06,410 names, swift tuples, and so much more. So as you can see, it's a jam-packed lesson full of advanced concepts. 223 224 00:18:06,440 --> 00:18:12,050 So, now that you've reached this stage in your development journey, it's really important that if there's 224 225 00:18:12,170 --> 00:18:17,360 anything that you don't fully understand, or if there's something that you want to learn more about, then 225 226 00:18:17,360 --> 00:18:23,390 be sure to do some extra reading, and especially by reading through the Swift Programming Language Online 226 227 00:18:23,390 --> 00:18:29,630 Book which you can access at docs.swift,org/swift-book, and you can look through it and 227 228 00:18:29,630 --> 00:18:34,970 read up on the parts that we've covered, and try it out yourself just so that you can make all of the 228 229 00:18:34,970 --> 00:18:37,140 knowledge in the tutorials your own. 229 230 00:18:37,190 --> 00:18:39,890 So it's all from me, Angela@theAppBrewery. 230 231 00:18:40,080 --> 00:18:41,420 So till next time, guys.