0 1 00:00:00,450 --> 00:00:08,580 Now, at this stage, your developer instincts should be tingling because we've created this entire app 1 2 00:00:08,970 --> 00:00:15,930 with just a single file, ViewController.swift. And all of our functionality, all of the components are 2 3 00:00:15,940 --> 00:00:19,650 living and sharing this tiny space of one file. 3 4 00:00:19,860 --> 00:00:26,760 So given that in the advanced section of our Swift Tutorials, we're talking a lot about architecture 4 5 00:00:26,970 --> 00:00:28,480 and design patterns, 5 6 00:00:28,560 --> 00:00:35,400 so that our app is well organized and extensible, then we should really be thinking about applying MVC 6 7 00:00:35,460 --> 00:00:38,860 or the model-view-controller pattern to our app. 7 8 00:00:38,880 --> 00:00:42,220 So let's go ahead and do that. As a challenge, 8 9 00:00:42,240 --> 00:00:48,900 can you create a new Swift File to create a separate class? And inside that class, we're going to put 9 10 00:00:48,900 --> 00:00:53,870 in all of the calculation logic that's currently inside the ViewController. 10 11 00:00:54,090 --> 00:00:59,750 So create a new class called Calculator Logic and put that into a new Swift File. 11 12 00:01:02,630 --> 00:01:02,930 All right. 12 13 00:01:02,930 --> 00:01:04,490 So this is pretty easy. 13 14 00:01:04,520 --> 00:01:09,590 We're just going to select the folder and I'm going to hit command Nto bring up the shortcut for 14 15 00:01:09,590 --> 00:01:13,810 creating a new file, and we're inside iOS Swift File. 15 16 00:01:13,910 --> 00:01:19,520 So if you're ever confused about whether if you should create a new Cocoa Touch Class or if you want 16 17 00:01:19,520 --> 00:01:26,480 to use a new Swift File, then remember that whenever you want to subclass something, such as a UIViewController, 17 18 00:01:26,810 --> 00:01:33,140 a UITableViewController, a UIView, whatever it may be, then you're going to choose this one. 18 19 00:01:33,290 --> 00:01:39,600 But when you create your own custom classes, then you're going to be choosing a boggled standard Swift File. 19 20 00:01:39,800 --> 00:01:45,380 So let's hit next and let's call this file Calculator Logic. 20 21 00:01:48,780 --> 00:01:52,060 And I'm going to move it right up close to my ViewController. 21 22 00:01:52,060 --> 00:01:55,560 Now, at this stage, I'm going to separate it out into MVC. 22 23 00:01:55,840 --> 00:02:01,660 So I'm going to right click on my CalculatorLogic file and I'm going to select New Group from selection, 23 24 00:02:01,960 --> 00:02:08,000 so that I can put it inside my Model file, and then I'm going to do the same with my ViewController, 24 25 00:02:08,500 --> 00:02:16,090 and that is going to be my Controller. And my Main.storyboard is going to be placed inside a View 25 26 00:02:16,180 --> 00:02:16,980 folder. 26 27 00:02:16,990 --> 00:02:26,350 So, now I have MVC and we're going to go into our Model and create a brand-new Swift class. 27 28 00:02:26,350 --> 00:02:32,500 Now, the class name is going to be the same as the name of the file, which is good programming practice, 28 29 00:02:32,590 --> 00:02:39,100 so that way when you look inside your file inspector over here, you can see at a glance all of the classes 29 30 00:02:39,100 --> 00:02:42,030 that you have included in your project. 30 31 00:02:42,120 --> 00:02:48,670 Now, my class is not going to inherit from any other superclass. So I'm just going to delete that placeholder. 31 32 00:02:49,000 --> 00:02:49,930 And there we have it. 32 33 00:02:49,960 --> 00:02:56,630 We have a brand-new class and we've separated all of our files into the MVC structure. 33 34 00:02:56,650 --> 00:03:03,160 Now, the next part you'll notice is that here I'm importing Foundation which is a library of code that 34 35 00:03:03,160 --> 00:03:05,280 includes all of the Swift code. 35 36 00:03:05,350 --> 00:03:07,830 But if you look inside View Controller.swift, 36 37 00:03:07,900 --> 00:03:10,710 you can see I'm importing UIKit. 37 38 00:03:10,720 --> 00:03:17,650 Now, this includes everything that's inside Foundation, but it also has a whole bunch of UI related things, 38 39 00:03:17,980 --> 00:03:21,790 such as UIViewController or a UILabel. 39 40 00:03:21,820 --> 00:03:27,860 Basically, every class that has UI to begin with it is inside UIKit and you'll need to import UIKit 40 41 00:03:28,210 --> 00:03:31,180 if you need to work with the user interface. 41 42 00:03:31,420 --> 00:03:34,650 Now, in our CalculatorLogic, we don't need to do any of that. 42 43 00:03:34,660 --> 00:03:37,110 So Foundation is perfectly fine. 43 44 00:03:37,240 --> 00:03:45,370 Now, the next step is we want to move all of this calculation-related code into our brand-new 44 45 00:03:45,370 --> 00:03:49,800 CalculatorLogic model. So see if you can complete this as a challenge, 45 46 00:03:49,900 --> 00:03:55,540 see if you can move all of this into our CalculatorLogic and make sure that it still works 46 47 00:03:55,540 --> 00:04:00,260 when you test the app. 47 48 00:04:00,460 --> 00:04:00,730 All right. 48 49 00:04:00,730 --> 00:04:08,650 So first things first, let's create a new function over here and let's call it calculate. Now, this calculate 49 50 00:04:08,650 --> 00:04:14,890 function is going to take a single parameter which is called symbol, and it's going to be in the form of 50 51 00:04:14,890 --> 00:04:16,890 a String. 51 52 00:04:16,900 --> 00:04:22,690 Now, my calculate function is where I'm going to transplant all of this code over. 52 53 00:04:22,690 --> 00:04:28,270 Now, you might think that you can just transplant everything including the "if let," but let me show you 53 54 00:04:28,270 --> 00:04:30,570 what happens when we do that. 54 55 00:04:30,580 --> 00:04:39,580 So if you ever want to refresh the app when your errors are not occurring, then just try and hit command B 55 56 00:04:39,580 --> 00:04:44,350 and all the errors that are not meant to be there should be cleared, and the errors that are meant 56 57 00:04:44,350 --> 00:04:46,300 to be there will show up. 57 58 00:04:46,300 --> 00:04:51,060 So the first issue we have is use of unresolved identifiers slender. 58 59 00:04:51,460 --> 00:05:00,250 And the problem is that that sender variable comes from this input here and it refers to the button that 59 60 00:05:00,250 --> 00:05:02,100 triggered the IBAction. 60 61 00:05:02,260 --> 00:05:04,790 So there is no such thing as sender over here. 61 62 00:05:04,990 --> 00:05:11,950 So we have to make sure that we actually keep the "if let" over here inside our ViewController right 62 63 00:05:11,950 --> 00:05:12,440 here. 63 64 00:05:12,700 --> 00:05:19,720 So we can't actually transplant that part over because we don't have an IBAction with a button that's 64 65 00:05:19,720 --> 00:05:25,590 going to act as the sender giving us the information about which button got tapped by the user. 65 66 00:05:25,810 --> 00:05:32,140 However, if the calc button gets pressed, then we can check to see if sender.currentTitle is not nil, 66 67 00:05:32,380 --> 00:05:39,190 and in that case, we'll bind it to something called calcMethod, and that is what we're going to pass 67 68 00:05:39,190 --> 00:05:42,050 over to our CalculatorLogic. 68 69 00:05:42,070 --> 00:05:44,880 So we have one extra bracket down here 69 70 00:05:44,890 --> 00:05:48,290 because, previously, I deleted the "if let," 70 71 00:05:48,340 --> 00:05:51,960 so make sure that we delete the bottom one as well. 71 72 00:05:51,970 --> 00:05:58,320 Now, the next step is you can see that there's quite a few of "Use of unresolved identifiers." 72 73 00:05:58,450 --> 00:06:02,330 And the thing that it doesn't know about is this thing called calcMethod. 73 74 00:06:02,590 --> 00:06:07,380 Well, inside this function, we've decided to call the calcMethod a symbol. 74 75 00:06:07,570 --> 00:06:12,620 So we need to replace all the instances where we've got calcMethod with symbol. 75 76 00:06:12,730 --> 00:06:19,720 So you can go ahead and hit command F to find this thing called calcMethod in this file. 76 77 00:06:19,930 --> 00:06:25,450 And if you click the dropdown, we can give it some replacement text, and we'll instead replace it with 77 78 00:06:25,540 --> 00:06:26,580 symbol. 78 79 00:06:26,620 --> 00:06:29,780 So let's replace that one, that one, and that one. 79 80 00:06:30,050 --> 00:06:36,700 And now, those errors will go away because we're going to pass in the calcMethod as a symbol parameter, 80 81 00:06:37,150 --> 00:06:41,440 and then we're going to check against that symbol inside this function. 81 82 00:06:41,440 --> 00:06:45,400 The next one that it doesn't recognize is this thing called displayValue. 82 83 00:06:45,580 --> 00:06:50,340 And if you remember, displayValue was our computed property up here, 83 84 00:06:50,620 --> 00:06:57,220 and we figured out what the value of it is by looking into the displayLabel and getting the current 84 85 00:06:57,220 --> 00:06:58,620 value. 85 86 00:06:58,630 --> 00:07:03,900 Now, we don't have a display label over here and we don't have a display value either. 86 87 00:07:04,000 --> 00:07:09,310 So we're going to have to create a new property inside this class and we'll just call it something simple 87 88 00:07:09,310 --> 00:07:10,840 like number. 88 89 00:07:11,080 --> 00:07:17,920 This is going to be of type Double and it's not going to have a value until we pass it over from the 89 90 00:07:17,920 --> 00:07:25,090 ViewController. So we can either set this to a optional Double, or as you can see, if I want to leave 90 91 00:07:25,090 --> 00:07:32,210 it as this, then it tells me that I have to initialize number when we create a new object from this class. 91 92 00:07:32,410 --> 00:07:39,760 So that means I have to add some init code. So I could say something like init(number) which is going 92 93 00:07:39,760 --> 00:07:45,770 to be a Double. And inside the init, I'm going to tap into self.number. 93 94 00:07:45,790 --> 00:07:50,400 Now, whenever you're using properties or methods associated with the current class, 94 95 00:07:50,410 --> 00:07:57,040 so in this case, CalculatorLogic, you can refer to the properties and methods with this keyword "self" 95 96 00:07:57,100 --> 00:07:58,120 in front of it. 96 97 00:07:58,120 --> 00:08:02,470 This means that we're looking inside the current class for something called number. 97 98 00:08:02,710 --> 00:08:08,170 And when you start typing number, you can see that in the left-hand side, we've got this "V" here, 98 99 00:08:08,290 --> 00:08:11,460 and this is telling us that this is a global variable. 99 100 00:08:11,710 --> 00:08:21,850 So if I hit enter, then I'm saying self.number, namely, this property should equal number, and that 100 101 00:08:21,850 --> 00:08:27,110 number is going to be passed in when CalculatorLogic gets initialized. 101 102 00:08:27,310 --> 00:08:34,180 And when I select it, you can see it's got a "L" symbol next to it which means that is a local variable 102 103 00:08:34,540 --> 00:08:37,240 which refers to this number. 103 104 00:08:37,240 --> 00:08:39,580 So while I can easily just write 104 105 00:08:39,580 --> 00:08:43,040 number = number, and it sort of makes sense, right? 105 106 00:08:43,040 --> 00:08:49,840 We're saying this left-hand side is this one. We're trying to set it to equal this one which is going 106 107 00:08:49,840 --> 00:08:53,170 to be the number that gets passed in through the init. 107 108 00:08:53,200 --> 00:09:00,790 Now, unfortunately, that does not make very much sense to either human or the computer, because even though 108 109 00:09:00,790 --> 00:09:06,370 they're named exactly the same, it's very, very confusing which one you're trying to set and which one 109 110 00:09:06,370 --> 00:09:12,040 you're trying to get. Now, one way of solving this is to simply make your global and local variables have 110 111 00:09:12,040 --> 00:09:17,470 different names. Because then you could say number = n and that's a lot clearer what it is that 111 112 00:09:17,470 --> 00:09:21,310 you're trying to change and what it is you're trying to grab the value for. 112 113 00:09:21,430 --> 00:09:28,720 Now, another way of addressing this is simply by adding the keyword "self" in front of the properties. 113 114 00:09:28,720 --> 00:09:35,860 So in this case, this is the property and we're saying "self," namely, in this current class, find a property 114 115 00:09:35,890 --> 00:09:41,600 called number, and there it is, and set it to equal the local version of number. 115 116 00:09:41,680 --> 00:09:44,740 So that is what the keyword "self" is for. 116 117 00:09:44,800 --> 00:09:49,010 It always refers to the current class, whatever it is that we're within. 117 118 00:09:49,090 --> 00:09:54,710 So, now we have a way of passing in a number to calculate. 118 119 00:09:54,760 --> 00:10:01,450 We have a function that performs the calculation and all we need now is just a way of giving the result 119 120 00:10:01,450 --> 00:10:02,050 back, 120 121 00:10:02,290 --> 00:10:05,970 and the result is probably going to be in the format of a Double. 121 122 00:10:06,040 --> 00:10:14,410 So we can fix these three lines of code that currently have errors to, instead, return the number multiplied 122 123 00:10:14,470 --> 00:10:16,220 by minus 1. 123 124 00:10:16,540 --> 00:10:25,030 So that means that if the user taps a 6, and then taps the "+/-" sign, then that 6 will 124 125 00:10:25,030 --> 00:10:31,110 get passed in as the number, and the "+/-" sign gets passed into this function. 125 126 00:10:31,480 --> 00:10:35,380 And if that is true, then we're going to return 6 126 127 00:10:35,440 --> 00:10:39,830 multiplied by minus 1 as the output of this function. 127 128 00:10:39,850 --> 00:10:44,450 So pause the video and go ahead and fix the last two lines. 128 129 00:10:44,670 --> 00:10:45,010 All right. 129 130 00:10:45,010 --> 00:10:48,550 So it's pretty easy. We just have to follow the format that we had before. 130 131 00:10:48,670 --> 00:10:54,260 So if they tapped on the AC button, then they simply want to change the display to zero. 131 132 00:10:54,310 --> 00:10:56,680 So we'll just return the number zero. 132 133 00:10:57,070 --> 00:11:04,690 And if they've tapped on the percentage button, then the result should be the number multiplied by 0.01. 133 134 00:11:04,690 --> 00:11:10,270 Now, once you get to the button here, it tells you that there's an error: Missing return in a function 134 135 00:11:10,270 --> 00:11:12,080 expected to return Double. 135 136 00:11:12,280 --> 00:11:15,330 Well, you might say that I've got loads of returns here, right? 136 137 00:11:15,340 --> 00:11:18,820 I've got return this, return that, return that. 137 138 00:11:18,820 --> 00:11:24,290 But notice how we have a if statement and two else if statements, 138 139 00:11:24,310 --> 00:11:30,670 there is still a possibility that we get a symbol passed in here that is not "+/-" not "AC," 139 140 00:11:30,670 --> 00:11:33,370 or the "%" sign. 140 141 00:11:33,370 --> 00:11:38,150 So in that case, then this function doesn't actually return anything. 141 142 00:11:38,170 --> 00:11:45,400 And so what we need to do is right at the end, if none of these other cases catches it, then we're simply 142 143 00:11:45,400 --> 00:11:46,970 going to return nil. 143 144 00:11:47,000 --> 00:11:52,930 Now, the next problem is that this function expects us to return a Double, 144 145 00:11:52,930 --> 00:11:53,240 right? 145 146 00:11:53,260 --> 00:11:56,800 And that's not an optional Double, that's just a normal Double, 146 147 00:11:56,800 --> 00:11:59,190 so it can't ever be nil. 147 148 00:11:59,200 --> 00:12:05,010 So in order to be able to return nil, then we have to change this into an optional Double. 148 149 00:12:05,170 --> 00:12:10,870 So there might be certain cases where we pass in a number and we try to perform a calculation on it 149 150 00:12:11,200 --> 00:12:15,760 that doesn't actually match any of these distinct cases that we've addressed. 150 151 00:12:15,760 --> 00:12:22,120 So in that case, we're simply going to return nil and we'll end up with a optional, and we'll deal with 151 152 00:12:22,120 --> 00:12:26,480 the optional on the other side inside the ViewController.swift. 152 153 00:12:26,710 --> 00:12:33,480 So, now that we've got our number, as well as our calculate function done inside our CalculatorLogic class, 153 154 00:12:33,820 --> 00:12:38,070 we can head back to our ViewController and call that function. 154 155 00:12:38,080 --> 00:12:45,880 So inside this "if let," if we actually have a title inside the button that triggered the 155 156 00:12:45,880 --> 00:12:51,360 calcButtonPressed IBAction, then we need to have a new instance of the calculator. 156 157 00:12:51,370 --> 00:12:52,850 So let's create that here. 157 158 00:12:53,050 --> 00:13:00,610 I'm going to create a new let constant called calculator and it's going to be a new instance of our class 158 159 00:13:00,640 --> 00:13:02,320 CalculatorLogic. 159 160 00:13:02,320 --> 00:13:08,500 And when I tried to initialize it, you can see that it's expecting a number to be passed in, and that 160 161 00:13:08,500 --> 00:13:11,860 number is going to be our displayValue. 161 162 00:13:12,130 --> 00:13:20,740 And so when I create my brand-new calculator, then this CalculatorLogic object will be able to have 162 163 00:13:20,980 --> 00:13:28,960 its number property initialized to whatever it is that I pass in here, and then the next step is to call 163 164 00:13:29,050 --> 00:13:34,080 the function that we created inside that object which was called calculate. 164 165 00:13:34,120 --> 00:13:41,110 So calculator.calculate, and the symbol that we want to pass over is this calcMethod because that is 165 166 00:13:41,110 --> 00:13:43,720 equal to the currentTitle of the sender. 166 167 00:13:43,990 --> 00:13:46,460 So let's go ahead and add that in here. 167 168 00:13:46,510 --> 00:13:52,350 And this, remember, has a output and this is what this little warning is telling you, 168 169 00:13:52,360 --> 00:13:55,590 "Result of call to calculate is unused." 169 170 00:13:55,600 --> 00:13:59,340 So what should we do with the result of the calculation? 170 171 00:13:59,380 --> 00:14:06,580 Well, we're going to assign it to our displayValue and we're going to set our displayValue to the calculation 171 172 00:14:06,580 --> 00:14:07,270 result. 172 173 00:14:07,540 --> 00:14:10,460 And remember, we have a didSet in here, 173 174 00:14:10,660 --> 00:14:17,410 so whenever we set this displayValue, then the value will populate our displayLabel. 174 175 00:14:17,410 --> 00:14:24,040 Now, the final thing we need to address is that do you remember how we made the output of our calculate 175 176 00:14:24,040 --> 00:14:26,370 function, a optional Double? 176 177 00:14:26,440 --> 00:14:31,690 Well, we have to deal with the situation where that might be nil, right? 177 178 00:14:31,990 --> 00:14:41,710 So we can simply add in a guard statement and we can say guard let results = calculator.calculate 178 179 00:14:41,950 --> 00:14:44,500 with the symbol, 179 180 00:14:44,660 --> 00:14:51,700 and if this fails, namely, if the result was nil, then we're going to throw a fatalError, 180 181 00:14:52,010 --> 00:15:03,760 and we're going to say, "The results of the calculation is nil," so that we can debug it if necessary. 181 182 00:15:04,160 --> 00:15:11,750 And now we can set our displayValue to results which is now a unwrapped Double, instead of what it used 182 183 00:15:11,750 --> 00:15:14,270 to be which was a optional Double. 183 184 00:15:14,300 --> 00:15:18,860 So let's run our app now and see if that did what we expected it to. 184 185 00:15:18,860 --> 00:15:19,150 All right. 185 186 00:15:19,150 --> 00:15:21,310 So let's try this with some numbers. 186 187 00:15:21,320 --> 00:15:30,590 Let's say 1.2 +/- becomes -1.2, and percentage becomes 0.012, 187 188 00:15:30,600 --> 00:15:34,470 and then AC sets it back to zero. 188 189 00:15:34,730 --> 00:15:42,530 So our code seems to be working just fine, but as we're on the advanced Swift section, it's a good time 189 190 00:15:42,530 --> 00:15:45,130 to think about our app's architecture. 190 191 00:15:45,140 --> 00:15:51,620 Up till now in the course, we've been creating classes for all of our models in our MVC. 191 192 00:15:52,010 --> 00:15:53,870 And this works just fine 192 193 00:15:54,000 --> 00:16:00,770 and makes our code comply with the model-view-controller design pattern that Apple is so fond of, but we 193 194 00:16:00,770 --> 00:16:09,210 can actually make our code a lot safer by simply changing our class into a struct. 194 195 00:16:09,380 --> 00:16:17,390 Now, to create a struct, which is short for a Swift structure, all we have to do is change this keyword 195 196 00:16:17,450 --> 00:16:22,550 from class to struct and this will turn it into a structure. 196 197 00:16:22,550 --> 00:16:28,730 Now, for those you guys who have worked with other programming languages, for example, C or C++ or even 197 198 00:16:28,740 --> 00:16:35,300 Objective-C, you'll think of struct as simply just the way of organizing little bits of data, just simply 198 199 00:16:35,330 --> 00:16:41,440 a way of grouping into related small pieces of data together into a structure. 199 200 00:16:41,690 --> 00:16:45,310 But struct in Swift is a little bit different. 200 201 00:16:45,470 --> 00:16:52,850 And over the years, Swift structures have morphed and changed many, many times, and with every iteration 201 202 00:16:52,850 --> 00:16:59,990 of the language, they've actually added more capabilities, more functionality to these structures to the 202 203 00:16:59,990 --> 00:17:06,410 point where we are right now where they're essentially as capable as any class, and they're no longer 203 204 00:17:06,440 --> 00:17:11,720 these little structures that just groups a little bit of data together. They're very much first-class citizens. 204 205 00:17:12,260 --> 00:17:18,710 You can create properties inside structures. You can create functions inside structures and they can 205 206 00:17:18,710 --> 00:17:22,340 be used absolutely any way, especially for your Data Models. 206 207 00:17:22,340 --> 00:17:29,330 Now, if you look inside the Swift standard library and you look at their definition for a string, for example, 207 208 00:17:29,720 --> 00:17:37,700 you can see that it's actually a struct, and so is a Double, and so are many, many other things that we've 208 209 00:17:38,030 --> 00:17:40,040 grown to rely on in Swift. 209 210 00:17:40,040 --> 00:17:46,730 So let's take a deeper dive into Swift structures and compare them against the classes that we now know 210 211 00:17:46,730 --> 00:17:51,560 and love, and see when we should be using a struct versus a class, 211 212 00:17:51,560 --> 00:17:53,410 and what are the pros and cons of each.