0 1 00:00:00,740 --> 00:00:01,080 All right. 1 2 00:00:01,080 --> 00:00:05,190 So you should have downloaded and unzipped or git cloned 2 3 00:00:05,220 --> 00:00:12,040 the calendar project to your desktop, and we're going to go ahead and open it up inside Xcode. 3 4 00:00:12,300 --> 00:00:18,380 So first things first, I just want to show you around the Main.storyboard that I've created here. 4 5 00:00:18,600 --> 00:00:23,820 Now, you'll notice that the design looks a little bit different from the one that we ended up with at 5 6 00:00:23,820 --> 00:00:25,950 the end of the Auto Layout module. 6 7 00:00:26,130 --> 00:00:31,320 And that's because I added a few more modifications just to make it look a little bit more realistic 7 8 00:00:31,680 --> 00:00:36,310 and more similar to the version of calculator that we've got on the Mac. 8 9 00:00:36,330 --> 00:00:44,030 So a couple of changes that I made are, firstly, I've reduced the space between all of the items inside our StackView. 9 10 00:00:44,070 --> 00:00:49,770 So when you click on any of these StackViews, you can see that the spacing is only one point between all 10 11 00:00:49,770 --> 00:00:50,970 of these gaps. 11 12 00:00:50,970 --> 00:00:57,780 I've also made the background view black so that these gaps show up as lines outlining each button for 12 13 00:00:57,780 --> 00:00:58,420 us. 13 14 00:00:58,720 --> 00:01:06,390 And I've also split up the bottom part by placing these two items in their own stack view, and then stacking 14 15 00:01:06,390 --> 00:01:12,330 that along with the 0 into another vertical stack, so now it distributes equally. 15 16 00:01:12,330 --> 00:01:18,210 And I've also changed the font to a thin font at 50 points and some of these other ones a little bit 16 17 00:01:18,210 --> 00:01:21,630 bigger as well, a system 30, for example. 17 18 00:01:21,630 --> 00:01:28,560 So now that we've taken a look at the design part, it's useful to take a look at what these parts are 18 19 00:01:28,560 --> 00:01:29,620 all linked to. 19 20 00:01:29,670 --> 00:01:33,310 So I've already created IBOutlets and IBActions. 20 21 00:01:33,360 --> 00:01:39,240 So the only outlet that we've got, currently, is the one that's linked to the displayLabel which is this 21 22 00:01:39,240 --> 00:01:45,330 one up here, and this displayLabel is going to be the one that's going to show up our results of our 22 23 00:01:45,330 --> 00:01:50,400 calculations, as well as the numbers that the user types into the keypad. 23 24 00:01:50,400 --> 00:01:52,380 Now, there's two IBActions. 24 25 00:01:52,470 --> 00:01:59,420 One of these IBActions are linked to all of the calculation buttons and it's called calcButtonPressed. 25 26 00:01:59,580 --> 00:02:05,310 And the other one is linked up to all of the number or the digit-related buttons, 26 27 00:02:05,430 --> 00:02:08,010 and it's called numButtonPressed. 27 28 00:02:08,010 --> 00:02:14,710 And we're going to be using these two methods in order to implement the functionality of our calculator, 28 29 00:02:14,850 --> 00:02:19,440 but it's important that you realize which buttons are linked to which method. 29 30 00:02:19,470 --> 00:02:21,870 So just familiarize yourself with that. 30 31 00:02:22,050 --> 00:02:27,230 So once you're ready, we can crack on and start building our calculator. 31 32 00:02:27,540 --> 00:02:34,530 So first things first, we want the user to be able to tap on any of these numbers and have it show up 32 33 00:02:34,650 --> 00:02:37,290 up here in the displayLabel. 33 34 00:02:37,290 --> 00:02:43,170 So as I mentioned before, the numButtonPressed is the action that's responsible to a tap on any of 34 35 00:02:43,170 --> 00:02:44,120 these buttons. 35 36 00:02:44,130 --> 00:02:48,950 So this is what should happen when a number is entered into the keypad. 36 37 00:02:49,140 --> 00:02:52,370 And this is also where we're going to add our code. 37 38 00:02:52,530 --> 00:02:58,740 So previously, in the Xylophone app, if you remember, we also had multiple buttons linked up to the same 38 39 00:02:58,950 --> 00:03:05,450 IBAction, and in that case, what we did was we gave each of these buttons a different Tag value. 39 40 00:03:05,760 --> 00:03:12,360 And by looking at what the Tag value of the sender was, we figured out which button was tapped on. 40 41 00:03:12,360 --> 00:03:19,200 Now, that's a little bit manual, and it involves you having to edit the tags manually one by one which 41 42 00:03:19,200 --> 00:03:20,630 is a bit of a pain. 42 43 00:03:20,640 --> 00:03:27,630 So as I always say, programmers are lazy, so what can we do that makes it a little bit easier and less 43 44 00:03:27,630 --> 00:03:28,410 manual? 44 45 00:03:28,410 --> 00:03:33,800 So I want to know the identity of the button that was tapped. 45 46 00:03:33,840 --> 00:03:38,320 And I know that that information is stored inside this object called sender. 46 47 00:03:38,640 --> 00:03:44,030 Now, the sender has a whole bunch of different properties, such as what is the background color, 47 48 00:03:44,040 --> 00:03:49,020 well, in this case, it's blue, or what is the size of the button, for example. 48 49 00:03:49,100 --> 00:03:55,860 Now, you can also see that these different buttons already have a title, right? 49 50 00:03:55,860 --> 00:03:58,090 They already have some text in them. 50 51 00:03:58,080 --> 00:04:05,070 And if I could just figure out what the text was of the button that triggered the IBAction, then that will 51 52 00:04:05,070 --> 00:04:09,660 be really helpful for me to implement my calculator functionality. 52 53 00:04:09,660 --> 00:04:17,790 So if we tap into the sender object and we use the dot to find all of its properties, even if you just 53 54 00:04:17,790 --> 00:04:25,170 start searching randomly for what you think could be the name of the property, Xcode is very helpful 54 55 00:04:25,200 --> 00:04:29,280 in pulling up all of the related properties and methods. 55 56 00:04:29,280 --> 00:04:33,980 So in my case, I kind of want to know what the title of that button is. 56 57 00:04:33,990 --> 00:04:40,040 So I might say sender.title and you can see that it's giving me a whole bunch of suggestions. 57 58 00:04:40,140 --> 00:04:44,960 Do I want the titleLabel? Do I want the title for UIControl.State? 58 59 00:04:44,970 --> 00:04:52,470 And you can see which ones are variables, which ones are methods. Or do I want the titleColor, titleRect? 59 60 00:04:52,650 --> 00:04:56,410 Now, you can see that there's two contenders in this case. 60 61 00:04:56,460 --> 00:05:03,950 One is the tie to a label, and this as it describes down here, is a view that displays the value of the 61 62 00:05:03,950 --> 00:05:06,620 current title property for a button. 62 63 00:05:06,650 --> 00:05:08,980 So we could go through it this way. 63 64 00:05:09,050 --> 00:05:12,450 But there's actually even better one if you scroll through this list. 64 65 00:05:12,620 --> 00:05:18,740 There's this one called current title and the description for this one is the current title that's displayed 65 66 00:05:18,860 --> 00:05:19,680 on the button. 66 67 00:05:19,700 --> 00:05:21,080 Well, that's perfect, right? 67 68 00:05:21,080 --> 00:05:25,910 That's exactly what we need in order to figure out which button was pressed. 68 69 00:05:25,910 --> 00:05:32,150 Now, there's a lot of documentation that you can look up online and you'll find all the help in the world 69 70 00:05:32,180 --> 00:05:35,990 on Stack Overflow and Google and blog posts 70 71 00:05:35,990 --> 00:05:42,680 but there's nothing that is quite as quick and easy as just searching for what you want and just coming 71 72 00:05:42,680 --> 00:05:49,220 up with a name that you think is likely, and then scrolling through that list for a good contender, 72 73 00:05:49,700 --> 00:05:57,220 just as we did here. So in my case, I want to set the display label's text to the current title of the button, 73 74 00:05:57,230 --> 00:06:01,160 so that means if the user taps 1, I want this to read 1. 74 75 00:06:01,280 --> 00:06:08,120 Now, I can do that by tapping into my IBOutlet displayLabel, and then going into its text property and 75 76 00:06:08,120 --> 00:06:11,360 setting that equal to sender.current title. 76 77 00:06:11,360 --> 00:06:13,970 Now, there's just one problem. 77 78 00:06:13,970 --> 00:06:22,250 If you hold down alt and click on current title, you can see that this is a String question mark, 78 79 00:06:22,340 --> 00:06:24,370 so this is an optional string. 79 80 00:06:24,650 --> 00:06:30,160 And if we read through the discussion, the last sentence says that the value may be nil. 80 81 00:06:30,170 --> 00:06:33,590 Well, what if we had a button that didn't actually have a title? 81 82 00:06:33,710 --> 00:06:37,240 Well, in that case, sender.currentTitle will be nil 82 83 00:06:37,460 --> 00:06:40,770 and this line of code will crash your app. 83 84 00:06:40,820 --> 00:06:45,290 Now, another neat thing that you can see now that you know all about computed properties is that you 84 85 00:06:45,290 --> 00:06:50,300 can see that this currenTitle property is a get-only property, 85 86 00:06:50,420 --> 00:06:51,940 so it's read-only. 86 87 00:06:51,950 --> 00:06:59,780 So that means we can't, for example, say, sender.currentTitle equals something, something, that doesn't 87 88 00:06:59,780 --> 00:07:07,450 work because as it suggests currentTitle is the currentTitle that's in the button, and it doesn't let 88 89 00:07:07,460 --> 00:07:11,350 you to give it a new value by setting it. 89 90 00:07:11,510 --> 00:07:18,110 And this is achieved through making currentTitle a computed property that only has a get defined and 90 91 00:07:18,110 --> 00:07:19,250 no set. 91 92 00:07:19,250 --> 00:07:24,770 So here's a little bit of a practical example of what we've been learning about in the last module. 92 93 00:07:24,770 --> 00:07:28,980 Now, in our case, I don't really want this line to crash. 93 94 00:07:29,150 --> 00:07:37,170 So what I want to do is I'm going to use a "if let" and I'm going to call it a numValue, 94 95 00:07:37,430 --> 00:07:39,610 so the number value. 95 96 00:07:39,980 --> 00:07:43,640 And I'm going to set that to equal the sender.currentTitle. 96 97 00:07:43,640 --> 00:07:48,260 And if this sender.currentTitle happens to be not nil, 97 98 00:07:48,260 --> 00:07:57,080 then inside the "if let" is where we're going to set the displayLabel.text to equal to that new 98 99 00:07:57,170 --> 00:08:04,250 unwrapped numValue. And you can see now numValue is just a bog-standard regular string as 99 100 00:08:04,250 --> 00:08:06,190 opposed to an optional string. 100 101 00:08:06,230 --> 00:08:09,740 So we can test our app and see what we get. 101 102 00:08:09,740 --> 00:08:12,850 All right, so here's our simulator on the left here, 102 103 00:08:13,010 --> 00:08:17,330 and I'm going to tap on the 7 and you can see 7 shows up in here. 103 104 00:08:17,510 --> 00:08:22,430 Now, this is just a bit of an issue with our app and I'm sure you can already see it. 104 105 00:08:22,430 --> 00:08:25,130 Now, what if I wanted two digits? 105 106 00:08:25,130 --> 00:08:32,000 Well, I can't at the moment. I can only put in one digit because I'm setting the displayLabel.text 106 107 00:08:32,090 --> 00:08:38,120 to equal whatever button was pressed through these three lines of code. 107 108 00:08:38,150 --> 00:08:39,970 So here's a challenge. 108 109 00:08:39,980 --> 00:08:48,260 Can you figure out a way of appending the numbers that the user keeps on tapping on, so that inside the 109 110 00:08:48,290 --> 00:08:52,790 displayLabel, we display the entire number that they wanted to put in? 110 111 00:08:52,790 --> 00:08:58,810 So for example, if I wanted to type 150, I should be able to see 150 show up up here. 111 112 00:08:58,970 --> 00:09:03,610 And to only set it back to nil or allow a new number to be entered 112 113 00:09:03,620 --> 00:09:07,100 when I click on any of these other buttons. 113 114 00:09:07,130 --> 00:09:11,360 So this is pretty much classic calculator functionality. 114 115 00:09:11,360 --> 00:09:13,850 You don't need me to go through it any more than that. 115 116 00:09:13,850 --> 00:09:17,550 So pause the video and see if you can complete that challenge. 116 117 00:09:20,420 --> 00:09:20,750 All right. 117 118 00:09:20,750 --> 00:09:28,580 So, basically, what we need to do is to append each of these numValues to each other and display it 118 119 00:09:28,640 --> 00:09:34,530 in the displayLabel until the user taps on one of these calculate buttons. 119 120 00:09:34,550 --> 00:09:40,960 So a typical case would be, say, for example, I'm trying to type in 150 plus 3, 120 121 00:09:41,000 --> 00:09:41,340 right? 121 122 00:09:41,450 --> 00:09:48,940 So when I type plus, then I can clear the 150, and I can start from scratch on the 3. 122 123 00:09:48,950 --> 00:09:56,000 So in order to do that, I need to have some sort of property that keeps hold of whether if the user is 123 124 00:09:56,000 --> 00:09:58,340 done typing the number. 124 125 00:09:58,670 --> 00:10:03,350 So let's go up here, and just below IBOutlet, 125 126 00:10:03,350 --> 00:10:09,960 let's create a new variable and let's call it isFinishedTypingNumber. 126 127 00:10:09,980 --> 00:10:15,290 This is a little bit wordy but, hey, we've got Xcode autosuggesting everything, so we don't have to type 127 128 00:10:15,290 --> 00:10:16,020 everything out, 128 129 00:10:16,160 --> 00:10:18,530 so why not make it super clear. 129 130 00:10:18,680 --> 00:10:25,900 So isFinishedTypingNumber is going to be a Boolean and it's going to start off in life as being true. 130 131 00:10:25,940 --> 00:10:31,630 So when we first start up our app, then isFinishedTypingNumber is going to be true. 131 132 00:10:31,850 --> 00:10:41,420 So, now we can go inside our numButtonPressed and we can check to see if isFinishedTypingNumber 132 133 00:10:42,050 --> 00:10:43,940 is equal to true. 133 134 00:10:43,940 --> 00:10:50,060 You can either use this full syntax where you have it checking with a double equals or you can simply 134 135 00:10:50,270 --> 00:10:57,310 just delete that and everything between the "if" keyword and the open curly brace is evaluated. 135 136 00:10:57,470 --> 00:11:02,030 And if it is true, then this block will be carried out, 136 137 00:11:02,210 --> 00:11:03,910 otherwise, it will not. 137 138 00:11:03,920 --> 00:11:09,730 So inside here if isFinishedTypingNumber is true, then that means we're just starting out, 138 139 00:11:09,890 --> 00:11:15,800 and the number in the label is probably 0 or we're just starting out with a new number that we want 139 140 00:11:15,800 --> 00:11:16,480 to type. 140 141 00:11:16,670 --> 00:11:23,450 So in that case, we do want to set the displayLabel.text to equal the numValue, so the value 141 142 00:11:23,450 --> 00:11:25,410 of the button that got pressed. 142 143 00:11:25,430 --> 00:11:33,470 So when I first start out the app, the display label says 0 and isFinishedTypingNumber is going 143 144 00:11:33,470 --> 00:11:34,950 to be initialized to true. 144 145 00:11:35,060 --> 00:11:41,600 So in this case, when I press one of the buttons, then that is the value that is going to go into this 145 146 00:11:41,690 --> 00:11:42,960 UILabel. 146 147 00:11:42,980 --> 00:11:47,510 Now, once we've set a number into the label, 147 148 00:11:47,570 --> 00:11:50,760 so the first number is showing up in there, 148 149 00:11:51,020 --> 00:11:59,510 then we have to switch this isfinishedTypingNumber to false, because we are not done typing the number, 149 150 00:11:59,510 --> 00:12:06,980 right? We've just typed in the first number, and until I press one of these buttons, the orange or the 150 151 00:12:06,980 --> 00:12:13,970 gray buttons, I want my calculator to accumulate all the numbers, so that I can type a number that is 151 152 00:12:13,970 --> 00:12:15,470 more than one digit. 152 153 00:12:15,470 --> 00:12:18,200 For example, I want to be able to type 150. 153 154 00:12:18,560 --> 00:12:22,060 So inside here, we can define our else case. 154 155 00:12:22,100 --> 00:12:29,720 So namely, when this IBAction is triggered and we are not finished typing number, we've just started typing 155 156 00:12:29,720 --> 00:12:30,400 a number, 156 157 00:12:30,650 --> 00:12:36,390 then we should be able to accumulate the number by appending them to the previous number. 157 158 00:12:36,590 --> 00:12:46,430 So in this case, then we can say displayLabel.text is equal to the current text in the displayLabel, 158 159 00:12:46,790 --> 00:12:52,080 plus, or rather append what is currently the numValue. 159 160 00:12:52,370 --> 00:12:59,360 So what this line of code will do is it will look at the currentTitle of the button that was pressed 160 161 00:12:59,870 --> 00:13:07,300 and it will append that value to what is currently inside the displayLabel here. 161 162 00:13:07,520 --> 00:13:12,710 So if I run this code now, you can see that when I type 1, 162 163 00:13:12,770 --> 00:13:18,390 now at this point isFinishedTypingNumber is set to false. 163 164 00:13:18,410 --> 00:13:25,520 So we're going to go inside this else bracket, and that means that the next button I press will get 164 165 00:13:25,760 --> 00:13:29,690 added or appended to the previous value of the displayLabel, 165 166 00:13:29,690 --> 00:13:38,200 and now I have 15. And if I keep going until 0, I can keep adding numbers and it will continue to append. 166 167 00:13:38,330 --> 00:13:45,620 Now, ideally, when I press any of these buttons, for example, plus, I want to be able to start typing a new 167 168 00:13:45,620 --> 00:13:48,990 number, instead of continuing to append numbers. 168 169 00:13:49,010 --> 00:13:54,490 So in order for that to happen, we have to go into our calcButtonPressed because, remember, this 169 170 00:13:54,500 --> 00:13:57,520 IBAction is linked to all of the calculation buttons. 170 171 00:13:57,830 --> 00:14:02,930 And here I'm going to set that variable isFinishedTypingNumber to 171 172 00:14:02,990 --> 00:14:03,860 true. 172 173 00:14:04,100 --> 00:14:11,390 Because if I've typed a whole bunch of numbers, and then I press the add button, then I'm pretty much finished 173 174 00:14:11,480 --> 00:14:12,560 typing number, right? 174 175 00:14:12,560 --> 00:14:16,120 I want to type a new number to add to my last number. 175 176 00:14:16,400 --> 00:14:22,540 So, now let's run our app with that minor update. Now, you can see I can type 150, 176 177 00:14:22,550 --> 00:14:29,910 and then when I press any of these buttons, say, plus, then I can add in a new number, 150 plus 250. 177 178 00:14:29,940 --> 00:14:35,320 Now, none of the equal signs or anything else works because we haven't implemented anything in there. 178 179 00:14:35,480 --> 00:14:42,110 But you can see I've already managed to use our variable isFinishedTypingNumber and toggling it state 179 180 00:14:42,230 --> 00:14:47,660 to be able to make my calculator accumulate numbers when I need it to, and to forget about the numbers 180 181 00:14:47,750 --> 00:14:49,320 when I need it to as well.