0 1 00:00:00,960 --> 00:00:01,260 All right. 1 2 00:00:01,260 --> 00:00:06,900 So, now that we've learned all about struct, it's time to come back to our calculator app and finish the 2 3 00:00:06,900 --> 00:00:08,800 rest of the functionality. 3 4 00:00:08,850 --> 00:00:16,410 So firstly, you would have noticed that I've changed the calculator logic from a class to a struct. 4 5 00:00:16,830 --> 00:00:23,220 And from our knowledge about structs, we now know that we don't actually need an initializer for our structs 5 6 00:00:23,340 --> 00:00:29,820 because we get a free one, right? And Xcode won't give us any errors or complaints because we're now using 6 7 00:00:29,880 --> 00:00:30,960 a struct. 7 8 00:00:30,960 --> 00:00:34,270 Now, there's other things that we can improve in our code as well. 8 9 00:00:34,320 --> 00:00:40,500 If you head over to the ViewController.swift, you can see that at the moment, we're initializing a brand-new 9 10 00:00:40,500 --> 00:00:46,740 CalculatorLogic structure every single time the calc button is pressed. 10 11 00:00:46,740 --> 00:00:48,480 Now, that's pretty inefficient. 11 12 00:00:48,660 --> 00:00:54,410 So let's move this out of the IBAction and let's just move it up here for now. 12 13 00:00:54,690 --> 00:01:00,180 So, now that it's outside this function, this is no longer a local variable. 13 14 00:01:00,210 --> 00:01:02,240 It's now a global variable. 14 15 00:01:02,370 --> 00:01:09,120 And that means that unless we change the access level, any other class could access our instance of the 15 16 00:01:09,120 --> 00:01:11,050 calculator and mess with it. 16 17 00:01:11,130 --> 00:01:12,720 That's not what we want. 17 18 00:01:12,750 --> 00:01:18,540 So let's go ahead and add that private keyword which we add in front of all of our global variables 18 19 00:01:18,570 --> 00:01:19,740 by default. 19 20 00:01:19,740 --> 00:01:28,350 Now, the next problem is that Xcode tells us that you cannot use display value within a property initializer 20 21 00:01:28,740 --> 00:01:33,180 because the property initializers run before 'self' is available. 21 22 00:01:33,180 --> 00:01:35,190 Now, what does all of that mean? 22 23 00:01:35,190 --> 00:01:42,240 Well, it means that because this is a global variable, which happens even before viewDidLoad gets called, 23 24 00:01:43,080 --> 00:01:50,940 the Swift compiler can be sure that display value is not nil at the point when you're trying to initialize 24 25 00:01:50,970 --> 00:01:52,570 CalculatorLogic. 25 26 00:01:52,620 --> 00:02:00,540 So depending on how long it takes to initialize the screen to call viewDidLoad, to do all of the prep work, 26 27 00:02:00,540 --> 00:02:07,740 then displayValue may or may not be nil when you're calling this line of code to create a new 27 28 00:02:07,740 --> 00:02:09,550 CalculatorLogic struct. 28 29 00:02:09,750 --> 00:02:12,560 And this means that we can't use it here. 29 30 00:02:12,660 --> 00:02:21,000 So let's fix this. Now, instead of passing in displayValue to initialize our calculator, 30 31 00:02:21,330 --> 00:02:27,660 let's go ahead and delete that, and instead, make our property number an optional. 31 32 00:02:27,660 --> 00:02:33,640 So this means that we can pass in a value to this property at a later point. 32 33 00:02:33,900 --> 00:02:41,600 And when this struct CalculatorLogic gets initialized, this number property can be nil. 33 34 00:02:41,730 --> 00:02:43,210 And that kind of makes sense, right? 34 35 00:02:43,230 --> 00:02:50,370 When you create a brand-new CalculatorLogic, if the user hasn't pressed any of the buttons on the calculator 35 36 00:02:50,370 --> 00:02:54,070 yet, then it shouldn't really have a number, right? 36 37 00:02:54,150 --> 00:03:02,690 But if this number is a Double, then before we use it, we have to check to make sure that it's not nil. 37 38 00:03:02,940 --> 00:03:12,810 So if let n = number, then that means that number is not nil, and we can now use it inside our 38 39 00:03:12,810 --> 00:03:21,150 code by replacing the places where we use number with this unwrapped n which is a double, rather than 39 40 00:03:21,330 --> 00:03:22,750 an optional double. 40 41 00:03:23,130 --> 00:03:25,700 So, now let's get back to our ViewController. 41 42 00:03:25,920 --> 00:03:32,370 Now, at this point, if you have any lingering errors, be sure to hit command B to force your app to build 42 43 00:03:32,670 --> 00:03:36,940 so that any of the errors that are no longer meant to be here gets removed. 43 44 00:03:37,100 --> 00:03:43,890 Now, the next thing I want to change is inside our struct CalculatorLogic.Our number property 44 45 00:03:43,920 --> 00:03:47,020 at the moment is a global variable. 45 46 00:03:47,150 --> 00:03:50,250 And do you remember what we said about global variables? 46 47 00:03:50,250 --> 00:03:58,410 They should always have the private access level by default because, otherwise, this property is accessible 47 48 00:03:58,410 --> 00:04:01,370 from all other classes within our app. 48 49 00:04:01,560 --> 00:04:08,430 And that means that it could get altered or changed or turned to nil intentionally or unintentionally, 49 50 00:04:08,550 --> 00:04:16,070 which is not what we want, because this property number is integral to our CalculatorLogic model. 50 51 00:04:16,140 --> 00:04:18,180 It's nobody else's business. 51 52 00:04:18,330 --> 00:04:26,370 So instead, we can create a function that allows other classes to set the value of this number property. 52 53 00:04:26,940 --> 00:04:29,050 So we can say setNumber, 53 54 00:04:29,190 --> 00:04:32,580 and as an input, we want to be able to pass in a Double. 54 55 00:04:32,580 --> 00:04:41,820 Now, at this stage, I can name my function setNumber(number: Double) and then do this. But that doesn't 55 56 00:04:41,940 --> 00:04:43,940 really read very well, does it? 56 57 00:04:43,980 --> 00:04:50,940 When I call the function, it's going to be something like setNumber number, and it's because this parameter 57 58 00:04:50,940 --> 00:04:53,540 name is completely unnecessary. 58 59 00:04:53,550 --> 00:05:03,510 So as it stands, if I wanted to set the number over here, I would have to call calculator.setNumber, and 59 60 00:05:03,510 --> 00:05:05,350 then pass in the number 60 61 00:05:05,360 --> 00:05:08,110 that I want to pass which will be the displayValue 61 62 00:05:08,130 --> 00:05:15,060 in this case. Now that works, but I don't actually need this parameter name because the name of the method 62 63 00:05:15,150 --> 00:05:20,170 is already explicit enough as to what this method does. 63 64 00:05:20,190 --> 00:05:27,450 So I'd really like to be able to delete this part. Now, in order to be able to call that method like this, 64 65 00:05:27,450 --> 00:05:32,620 then over here, I can add an underbar, and then a space, 65 66 00:05:32,790 --> 00:05:39,030 and you might have seen the syntax across other Xcode projects, especially Apple's example projects. They 66 67 00:05:39,030 --> 00:05:40,210 love doing this. 67 68 00:05:40,570 --> 00:05:46,620 And what this means is that we're setting the external parameter name to be nothing, 68 69 00:05:47,100 --> 00:05:53,310 and we're setting the internal parameter name because you always need one inside to be able to use the 69 70 00:05:53,310 --> 00:05:57,410 thing that got passed in, right, to number. 70 71 00:05:57,880 --> 00:06:07,000 So if I changed this to, I don't know, num, and I have a setNumber, parentheses, num number, then that means 71 72 00:06:07,030 --> 00:06:12,320 my external parameter name is num and my internal name is number. 72 73 00:06:12,520 --> 00:06:19,090 So inside the curly braces, I will refer to the item that was passed into this function as number, and 73 74 00:06:19,240 --> 00:06:21,700 outside of the parameter name, 74 75 00:06:21,820 --> 00:06:24,580 then I would refer to it as num. 75 76 00:06:24,670 --> 00:06:27,500 But we wanted to not have a parameter name. 76 77 00:06:27,580 --> 00:06:33,820 So we're going to change the external one to an underscore. And instead of printing the number that got 77 78 00:06:33,820 --> 00:06:40,620 passed in, we want to set this private property to equal the value that was passed in. 78 79 00:06:40,630 --> 00:06:43,180 Now, in order to achieve that, I would write something like 79 80 00:06:43,180 --> 00:06:50,940 number = number which is really confusing, because which number is which? 80 81 00:06:50,950 --> 00:06:56,650 Which one of my setting? Am I trying to set this number or am I trying to set this number? And you can see, 81 82 00:06:56,650 --> 00:07:02,350 Swift actually gives you an error saying that number is a let constant because it thinks that you're trying 82 83 00:07:02,350 --> 00:07:04,230 to change this value. 83 84 00:07:04,330 --> 00:07:11,820 So what we do in this case? If we wanted to refer to this global property, we can simply say 84 85 00:07:11,830 --> 00:07:14,420 self.number is equal to number. 85 86 00:07:14,770 --> 00:07:22,090 And this means that anybody else who's looking at your code knows that I'm looking for a property inside 86 87 00:07:22,150 --> 00:07:28,090 the current class or the current struct namely inside the curly braces 87 88 00:07:28,150 --> 00:07:36,160 that's called number which is, of course, this one on line 13. And I'm setting it to equal the number that 88 89 00:07:36,220 --> 00:07:39,980 is the local variable which is this one. 89 90 00:07:40,010 --> 00:07:45,010 Now, the next problem we have is it tells us "Cannot assign to property: 90 91 00:07:45,010 --> 00:07:49,620 'self' is immutable. Mark method 'mutating' to make 'self' mutable." 91 92 00:07:49,660 --> 00:07:51,330 So you should be familiar with this already 92 93 00:07:51,340 --> 00:07:56,350 because we saw this when we were learning about struct, because we're creating this function 93 94 00:07:56,560 --> 00:07:58,920 inside our Swift structure. 94 95 00:07:59,230 --> 00:08:04,430 And this line of code modifies one of the properties of the struct. 95 96 00:08:04,450 --> 00:08:12,310 So if you remember, when you use a struct or when you pass around a struct, it does so by copying all 96 97 00:08:12,310 --> 00:08:13,550 of the values. 97 98 00:08:13,570 --> 00:08:21,460 So if this number had a value, say, it was 2, and this method inside the struct actually needs to change the 98 99 00:08:21,460 --> 00:08:31,150 value of this property to, say, 3, then this method has to be marked with mutating. Because this tells a 99 100 00:08:31,150 --> 00:08:37,560 Swift compiler that this method is capable of changing the properties inside the struct. 100 101 00:08:37,750 --> 00:08:42,130 And that means that it knows to make a brand-new copy of the struct 101 102 00:08:42,250 --> 00:08:49,030 when this function is run, so that it can update the property. Now, by doing that, we've created one more 102 103 00:08:49,030 --> 00:08:50,220 problem for ourselves. 103 104 00:08:50,260 --> 00:08:56,170 If you head back over to ViewController.swift, you can see that Xcode gives us an error saying that 104 105 00:08:56,170 --> 00:09:04,540 you cannot use a mutating member on an immutable value because calculator is a 'let' constant. 105 106 00:09:04,540 --> 00:09:05,490 What does that mean? 106 107 00:09:05,590 --> 00:09:12,850 Well, here,we're calling this function called setNumber which, remember, is a mutating function. 107 108 00:09:12,910 --> 00:09:20,500 It changes one of the properties of our struct. And in the last lesson, we spoke about what made structs 108 109 00:09:20,590 --> 00:09:22,050 different from classes, 109 110 00:09:22,240 --> 00:09:26,350 and one of those things was that they have true immutability. 110 111 00:09:26,350 --> 00:09:34,540 So that means that if you create a new structure that is declared as a "let" constant, then you can't change 111 112 00:09:34,810 --> 00:09:38,730 any of the properties inside that struct at a later point. 112 113 00:09:38,740 --> 00:09:44,980 So when we call this function and it changes our property, then this is why Xcode is getting angry at 113 114 00:09:44,980 --> 00:09:49,340 us, because you said that you weren't going to change this calculator ever, 114 115 00:09:49,360 --> 00:09:50,550 right? 115 116 00:09:50,560 --> 00:09:53,120 So Xcode could be really passive-aggressive like that. 116 117 00:09:53,200 --> 00:10:00,040 But let's go ahead and fix it to make it happy because, as we all know, a happy Xcode equals a happy 117 118 00:10:00,040 --> 00:10:01,230 app developer, right? 118 119 00:10:01,420 --> 00:10:04,360 So let's just quickly recap what we've done so far. 119 120 00:10:04,390 --> 00:10:11,800 We've created this global variable that is called calculator and it's a new instance of our struct 120 121 00:10:11,800 --> 00:10:18,200 CalculatorLogic, and we've marked it as private to prevent other classes from messing with our calculator. 121 122 00:10:18,370 --> 00:10:26,350 Now, when one of the calculation buttons gets pressed, then we call the setNumber function which sets 122 123 00:10:26,620 --> 00:10:33,150 the number inside CalculatorLogic to whatever is currently inside the display. 123 124 00:10:33,160 --> 00:10:38,390 So let's say that on our calculator, the user taps on the number 5. 124 125 00:10:38,620 --> 00:10:45,360 At this point in our code, we set the display value to 5. Next, the user taps on the plus sign. 125 126 00:10:45,460 --> 00:10:52,810 And because this is one of the calculate buttons, then our IBAction calcButtonPressed will get called. 126 127 00:10:53,200 --> 00:11:01,230 And inside that IBAction, we call setNumber on our calculator structure and we set the number in the 127 128 00:11:01,230 --> 00:11:08,770 calculator to 5. And then we also call the calculate function passing in that plus sign as the symbol. 128 129 00:11:09,090 --> 00:11:11,910 Next, the user taps on 3. 129 130 00:11:12,300 --> 00:11:18,040 At this point, we set the display value to 3. And finally, they tap on the equal sign. 130 131 00:11:18,180 --> 00:11:25,050 So the calcButtonPressed IBAction gets called yet again, and we set our calculator's number property 131 132 00:11:25,110 --> 00:11:31,600 to 3, and we call the calculate function, again, passing in the symbol equals. 132 133 00:11:31,710 --> 00:11:40,290 So when they tap on the plus button, we need to save that data somewhere in our CalculatorLogic. 133 134 00:11:40,290 --> 00:11:46,470 We need to save the first number that they wanted to calculate and the calculation that they wanted 134 135 00:11:46,470 --> 00:11:48,670 to make which is to add. 135 136 00:11:48,840 --> 00:11:53,860 Now, I could say that all in separate properties, right, up here, 136 137 00:11:54,000 --> 00:12:01,490 or I could create a brand-new struct that contains the first number and the operation they want to make. 137 138 00:12:01,620 --> 00:12:03,130 But that seems a bit overkill. 138 139 00:12:03,150 --> 00:12:07,630 Now, what's in between creating a new struct and creating a simple property? 139 140 00:12:07,740 --> 00:12:14,100 Well, in Swift, we have something called tuples, and that is what we're going to learn about in the next 140 141 00:12:14,100 --> 00:12:14,730 episode. 141 142 00:12:14,820 --> 00:12:17,340 So for all of that and more, I'll see you there.