0 1 00:00:00,580 --> 00:00:08,410 So up till now, we've created a brand-new TableViewController that's embedded inside a navigation 1 2 00:00:08,410 --> 00:00:08,650 controller. 2 3 00:00:09,160 --> 00:00:12,580 So we have this top bar here for our Todoey app. 3 4 00:00:12,580 --> 00:00:20,170 We've added items that have been hardcoded and we're able to now select them and add a checkmark, or 4 5 00:00:20,170 --> 00:00:23,310 deselect them and remove the checkmark. 5 6 00:00:23,320 --> 00:00:28,930 Now, let's go back to our TodoListViewController and add some more functionality. 6 7 00:00:28,930 --> 00:00:37,150 We wanted to be able to have a button on our app that allows us to add new items to our to-do list. 7 8 00:00:37,240 --> 00:00:45,290 So the easiest way of achieving this is by adding a bar button item to our TodoListViewController. 8 9 00:00:45,310 --> 00:00:53,920 So if we go ahead and search for a bar button item and we can drag it up to the top right here of our 9 10 00:00:53,920 --> 00:01:01,590 top bar, and I'm going to change the system item to add to get this nice little plus sign, 10 11 00:01:01,930 --> 00:01:09,030 and I'm also going to change the tint to white so that it matches my current palette. 11 12 00:01:09,190 --> 00:01:16,180 So, now that I've got that going on, I'm going to link this into my file as an IBAction. 12 13 00:01:16,180 --> 00:01:21,620 So I'm going to scroll down all the way to the bottom, I'm going to make a new pragma MARK, 13 14 00:01:22,000 --> 00:01:30,670 and this is going to be the "Add New Items" section. And then I'm going to create my IBAction right here, 14 15 00:01:30,670 --> 00:01:38,860 I'm going to change from outlet to action, and let's call it addButtonPressed, 15 16 00:01:38,860 --> 00:01:47,200 change it from any to more specific UI button BarButtonItem, and hit Connect. 16 17 00:01:47,420 --> 00:01:54,110 So, now I've got this brand new IBAction where I can add code to determine what should happen when the 17 18 00:01:54,110 --> 00:02:03,620 user presses that addButton. Here, what I want to happen is for a pop-up or a UIAlertController to 18 19 00:02:03,620 --> 00:02:11,990 show when I press the addButton and to have a text field in that UIAlert, so that I can write a quick 19 20 00:02:11,990 --> 00:02:18,560 to-do list item, and then append it to the end of my itemArray. 20 21 00:02:18,560 --> 00:02:26,160 So let's create a brand-new alert, so let alert = UIAlertController, 21 22 00:02:26,480 --> 00:02:31,300 and it's going to be the one with title message and preferred style. 22 23 00:02:31,370 --> 00:02:38,930 So the title will be something like "Add New Todoey Item," and the message, 23 24 00:02:38,930 --> 00:02:46,420 I'm actually going to leave blank, and the preferredStyle is just going to be alert, the default style. 24 25 00:02:46,820 --> 00:02:49,620 And then I'm gonna create an action, 25 26 00:02:49,790 --> 00:02:58,040 so this is gonna be a UIAlertAction and this action is going to have a title, a style, and a handler. 26 27 00:02:58,760 --> 00:03:02,900 So the title will be "Add Item." 27 28 00:03:02,900 --> 00:03:07,820 So this is gonna be the button that you're gonna press once you're done with writing your new to-do 28 29 00:03:07,820 --> 00:03:08,940 list item. 29 30 00:03:09,050 --> 00:03:13,660 The style is going to be default. And the handler, 30 31 00:03:13,670 --> 00:03:17,620 I'm just going to select this placeholder, so make it blue, 31 32 00:03:17,630 --> 00:03:26,720 I'm gonna hit enter to create a completion handler or a closure. So the action, I'm going to name action. 32 33 00:03:27,190 --> 00:03:30,590 I'm gonna delete the code placeholder. 33 34 00:03:30,590 --> 00:03:44,560 And here is gonna be "what will happen once the user clicks the Add Item button on our UIAlert." 34 35 00:03:44,570 --> 00:03:50,750 So, now let's add the action to our alert, addAction, 35 36 00:03:50,750 --> 00:03:53,390 the action is called action. 36 37 00:03:53,390 --> 00:03:55,040 Now, this is all very well and good, 37 38 00:03:55,070 --> 00:04:00,910 and we can check to make sure that it works by saying print "Success." 38 39 00:04:01,670 --> 00:04:04,820 And finally, we need to show our alert. 39 40 00:04:05,090 --> 00:04:12,170 So we're simply going to say present, and it's a viewController that we want to present, and the 40 41 00:04:12,190 --> 00:04:19,880 viewController to present, and the viewController is, of course, our alertViewController, animated: true, and completion: 41 42 00:04:19,940 --> 00:04:21,550 nil. 42 43 00:04:21,560 --> 00:04:24,880 Now, let's hit run and see what we've got so far. 43 44 00:04:25,070 --> 00:04:29,870 So we've got this brand-new add button as a bar button item 44 45 00:04:29,870 --> 00:04:34,970 and when we click on it, we activate this IBAction and we've created this brand-new alert. 45 46 00:04:35,990 --> 00:04:43,640 So, now when we click add item, all we get is just success printed to the debug console and nothing else. 46 47 00:04:43,640 --> 00:04:51,410 Now, what I want to happen next is, instead of just having a simple UI alert, I want to include a text 47 48 00:04:51,410 --> 00:04:58,880 field in this alert so that I can get the user to write a new to-do list item, and then when I click 48 49 00:04:58,940 --> 00:05:05,960 an item, I'm going to print what they wrote into the debug console here. In order to add a text field 49 50 00:05:06,050 --> 00:05:07,560 to our alert, 50 51 00:05:07,580 --> 00:05:15,650 it's very similar to adding an action, but all we have to do is say, alert.addTextField, and in the 51 52 00:05:15,650 --> 00:05:22,580 completion handler, we're going to select this placeholder and make it blue, and then hit enter to insert 52 53 00:05:22,850 --> 00:05:24,350 that closure. 53 54 00:05:24,350 --> 00:05:32,460 We're going to call the text field that we create alertTextField. And in the completion block, we're 54 55 00:05:32,460 --> 00:05:35,490 going to set up the alertTextFields. 55 56 00:05:35,490 --> 00:05:38,850 We're going to say alertTextField.placeholder. 56 57 00:05:38,970 --> 00:05:44,250 So this is the string that's going to show in gray and it's going to disappear when the user clicks 57 58 00:05:44,250 --> 00:05:45,320 on that text field. 58 59 00:05:45,420 --> 00:05:53,280 So a placeholder is going to say something like "Create new item," and then we're going to print whatever 59 60 00:05:53,280 --> 00:05:57,250 text is inside the alertTextField, so alertTextField.text. 60 61 00:05:57,660 --> 00:06:01,360 So let's go ahead and run this and see what happens. 61 62 00:06:02,760 --> 00:06:04,760 So let's click the Add button. 62 63 00:06:04,950 --> 00:06:11,550 You can see now we have a UIAlert that has a title, a new text field, and also a button. 63 64 00:06:11,550 --> 00:06:15,000 So it's got that placeholder there where it says, "Create new item." 64 65 00:06:15,060 --> 00:06:19,020 And as soon as we start typing, that placeholder is going to disappear. 65 66 00:06:19,020 --> 00:06:28,450 So let's say our new item is "Save the world!" and if I click add item, that disappears. 66 67 00:06:28,540 --> 00:06:34,930 And the problem that we have is that the point at which we click that button, we can write some code 67 68 00:06:35,440 --> 00:06:38,800 that specifies what should happen 68 69 00:06:39,010 --> 00:06:47,350 once the user clicks the add Item button on our alert. But the alertTextField is created as a local 69 70 00:06:47,350 --> 00:06:50,600 variable only inside this closure. 70 71 00:06:50,620 --> 00:06:56,590 So how do I grab what exists in here and print it 71 72 00:06:56,590 --> 00:07:00,550 once the user presses the ad Item button? 72 73 00:07:00,580 --> 00:07:02,610 So this is a bit of a tricky question. 73 74 00:07:02,650 --> 00:07:07,380 And you can have a think about it and see if you can figure it out, 74 75 00:07:07,420 --> 00:07:13,210 then this is a good time point to pause the video. But if you want to follow along with me, then I'm going 75 76 00:07:13,210 --> 00:07:15,630 to show you the solution. 76 77 00:07:15,640 --> 00:07:21,910 So, essentially, what we need is a local variable inside this IBAction. 77 78 00:07:21,910 --> 00:07:30,100 So inside the scope between these two curly braces that's accessible to all of these other completion 78 79 00:07:30,100 --> 00:07:30,970 handlers. 79 80 00:07:30,970 --> 00:07:38,140 So currently, I've got this alertTextField that has the scope of just this closure. And if I want to 80 81 00:07:38,140 --> 00:07:45,580 change it's very, very limited scope, i.e., being available just inside here, then I have to create a local 81 82 00:07:45,580 --> 00:07:54,210 variable within the scope of this addButtonPressed, so anywhere that's outside of one of these closures. 82 83 00:07:54,220 --> 00:08:02,620 So what we can do is we can create a textField up here which is going to be a UITextField and we're 83 84 00:08:02,620 --> 00:08:05,470 going to initialize it to an empty UITextField. 84 85 00:08:05,470 --> 00:08:13,480 Now, this text field has the scope of the entire addButtonPressed IBAction and is going to be 85 86 00:08:13,480 --> 00:08:17,490 accessible inside here as well as inside here. 86 87 00:08:17,530 --> 00:08:24,970 Now, at this stage, what we can do is we can set this text field with a wider scope to equal 87 88 00:08:24,970 --> 00:08:31,540 the alertTextField that has a slightly narrower scope because it's only available inside here. 88 89 00:08:31,540 --> 00:08:35,860 So if you write alertTextField, you can see the autosuggests come up here, 89 90 00:08:35,860 --> 00:08:43,150 but if you tried it outside the closure, alertTextField, nothing happens because it doesn't exist outside 90 91 00:08:43,330 --> 00:08:44,800 the scope of this closure. 91 92 00:08:45,280 --> 00:08:52,440 So we're extending the scope of that alertTextField to this addButtonPressed. 92 93 00:08:52,480 --> 00:08:56,600 Now, the sequence of events matters a great deal. 93 94 00:08:56,650 --> 00:09:03,310 You might think that you can simply write print(alertTextField.text) 94 95 00:09:03,380 --> 00:09:09,890 but the reason why this is not going to print you what the users typed into that text field is because 95 96 00:09:09,890 --> 00:09:16,970 this closure only gets triggered once the text field has been added to the alert. 96 97 00:09:16,970 --> 00:09:20,000 So it's at this time point when it happens. 97 98 00:09:20,420 --> 00:09:28,370 And what we can do is we can print something to our debug console to see when this closure gets triggered. 98 99 00:09:28,430 --> 00:09:34,580 So if I hit run, and let's just move that over here and make our debug console a little bit bigger, 99 100 00:09:34,580 --> 00:09:44,840 now I'm gonna click add, and you can see that this line here where it says, "optional empty string," refers 100 101 00:09:44,840 --> 00:09:46,550 to this print statement. 101 102 00:09:46,550 --> 00:09:52,580 It's trying to print the text that's currently inside the alertTextField which is, of course, empty. 102 103 00:09:53,270 --> 00:10:01,160 And we get the "Now" printed at the point when are text field is added to the alert, 103 104 00:10:01,190 --> 00:10:03,090 so when it shows up here. 104 105 00:10:03,380 --> 00:10:10,700 But when we type something in here and we click add item, nothing happens, there's no print statement that 105 106 00:10:10,700 --> 00:10:17,840 happens, because that time point is covered by this completion block when the user clicks the add Item 106 107 00:10:17,840 --> 00:10:18,910 button. 107 108 00:10:18,920 --> 00:10:25,490 This is the place that we're going to get something happening and we can show that by just using a 108 109 00:10:29,000 --> 00:10:30,760 print statement here. 109 110 00:10:30,980 --> 00:10:36,320 So you can see that as soon as I press the add button, that's when the "Now" gets printed. 110 111 00:10:36,320 --> 00:10:44,000 But when I click the add item, that's the point where we get the add item pressed printed because this 111 112 00:10:44,000 --> 00:10:52,190 is the completion blog that gets called once that add Item button gets pressed. So we can solve that timing 112 113 00:10:52,190 --> 00:11:01,820 problem by simply storing a reference to that alertTextField inside a local variable that's available 113 114 00:11:01,910 --> 00:11:05,330 to everybody inside the addButtonPressed. 114 115 00:11:05,510 --> 00:11:09,290 And this text field is what we're going to print inside here. 115 116 00:11:09,320 --> 00:11:18,170 So we're going to say print(textField.text) instead of this print statement. And I'm going to delete 116 117 00:11:18,200 --> 00:11:22,700 that print "Now" as well, and I'm going to hit run. 117 118 00:11:22,700 --> 00:11:28,290 So, now when I pressed the Add button, I don't get anything printed in here, 118 119 00:11:28,490 --> 00:11:38,690 othe than not very useful messages from Xcode. But if I now write something in here and I click the Add Item button, 119 120 00:11:39,560 --> 00:11:46,300 I get whatever I typed into that text field, print it out here because of this print statement. 120 121 00:11:47,660 --> 00:11:54,650 If that seemed confusing, it might be a good point to review the lessons on scope that we covered earlier 121 122 00:11:54,650 --> 00:11:55,710 on. 122 123 00:11:55,850 --> 00:12:04,760 Now, it's really important that you understand where these local variables are available and how you 123 124 00:12:04,760 --> 00:12:08,990 can use them to store data and read data. 124 125 00:12:09,590 --> 00:12:17,390 So instead of this print statement, what we actually want to happen is we want to add whatever text the 125 126 00:12:17,390 --> 00:12:24,190 user created to our itemArray and append it into this array at the end. 126 127 00:12:24,200 --> 00:12:33,050 Now, before we can append an item to our itemArray, we first have to change this array from being immutable 127 128 00:12:33,350 --> 00:12:40,730 because it's a constant to mutable by getting rid of that "let" and changing it to a "var." 128 129 00:12:40,760 --> 00:12:48,590 So, now what we can do is we can say itemArray.append, and the new element that we want to append 129 130 00:12:48,890 --> 00:12:57,230 has to be a string and it's going to be textField.text and we're going to force unwrap that because 130 131 00:12:57,290 --> 00:13:03,770 the text property of a text field is never going to equal nil, even if it's empty, it's going to be set 131 132 00:13:03,830 --> 00:13:05,210 to an empty string. 132 133 00:13:05,210 --> 00:13:10,270 Now, you can add some more checking code in here to maybe prevent the action from going forwards 133 134 00:13:10,430 --> 00:13:14,210 if the text field was empty or add some more validation code. 134 135 00:13:14,510 --> 00:13:21,140 But for now, we're just going to say that if the user entered nothing, it will just simply have an empty 135 136 00:13:21,140 --> 00:13:21,850 cell. 136 137 00:13:21,860 --> 00:13:25,400 Now, it's not ideal and there's quite a few workarounds to this. 137 138 00:13:25,400 --> 00:13:29,560 For example, we can give it a default value if it was nil. 138 139 00:13:29,570 --> 00:13:36,830 So we can say if textfield.text was nil, then simply append the string "New item." 139 140 00:13:36,830 --> 00:13:40,640 Now, that doesn't really look much better than an empty string, 140 141 00:13:40,640 --> 00:13:42,520 so that's not a great solution. 141 142 00:13:42,560 --> 00:13:48,620 A more sophisticated solution would be to prevent the action from going through if the textField.text 142 143 00:13:48,740 --> 00:13:50,030 was empty. 143 144 00:13:50,150 --> 00:13:52,160 But that's going to take a lot more lines of code. 144 145 00:13:52,190 --> 00:13:55,790 And right now, we want to focus on our objective here. 145 146 00:13:55,970 --> 00:14:02,720 So itemArray.append(textField.text!) And because I'm inside a closure, remember, the "in" keyword, 146 147 00:14:03,200 --> 00:14:11,030 I have to specify "self" to tell the compiler explicitly where this itemArray exists, i.e., in the current 147 148 00:14:11,030 --> 00:14:11,640 class. 148 149 00:14:11,660 --> 00:14:20,600 So, now if I run my app, you might expect it to work because we're pending whatever the user adds in 149 150 00:14:20,600 --> 00:14:28,610 the text field to this array and our tableView cellForRowAt indexPath uses this array. But as you'll 150 151 00:14:28,610 --> 00:14:39,600 shortly see, if I click on the add button and I add a new item, and I click Add Item, nothing changes in 151 152 00:14:39,600 --> 00:14:43,620 my table view. Table view hasn't changed one bit, 152 153 00:14:43,710 --> 00:14:52,230 despite the fact that we've added what the user wrote in the text field into our itemArray and our 153 154 00:14:52,230 --> 00:15:01,290 cell's textLabel is created from the itemArray. But if you'll believe me, I can tell you that it's definitely 154 155 00:15:01,290 --> 00:15:07,010 been added to this itemArray. So why is it not showing up in our table view? 155 156 00:15:07,350 --> 00:15:10,720 If you don't want to believe me, that's also perfectly valid. 156 157 00:15:10,770 --> 00:15:14,250 It's always good idea to test and not trust. 157 158 00:15:14,250 --> 00:15:22,620 So what I can do is I can put a breakpoint at this line where we've appended that item, and I can stop 158 159 00:15:22,620 --> 00:15:32,720 the app and run the app again. I'm going to add a new item, and once I hit Add Item 159 160 00:15:32,730 --> 00:15:38,490 same as before, but we now enter our debug session because our breakpoint is triggering it. 160 161 00:15:38,550 --> 00:15:46,530 So at the moment, before this line is carried out, and I print in my debug console the current value of 161 162 00:15:46,590 --> 00:15:49,740 itemArray and I hit enter, 162 163 00:15:49,740 --> 00:15:54,220 you can see that it's only got three items: "Find Mike," "Buy Eggos," "Destroy Demogorgon." 163 164 00:15:54,750 --> 00:16:01,530 Now, if I choose to step over this instruction, so carry it out, 164 165 00:16:01,710 --> 00:16:07,470 now if I hit print itemArray, hit enter, 165 166 00:16:07,590 --> 00:16:14,370 you can see I've now got four items, and that item has been added to my array itemArray. 166 167 00:16:14,610 --> 00:16:16,980 So, now I hope you'll believe me. 167 168 00:16:17,130 --> 00:16:19,410 But what do we do about this? 168 169 00:16:19,410 --> 00:16:26,920 How can we get it to show up in our table view? And the magic method is reload data. 169 170 00:16:27,060 --> 00:16:33,600 And this reloads the rows and the sections of the table view, taking into account the new data that we've 170 171 00:16:33,660 --> 00:16:35,690 added to our itemArray. 171 172 00:16:35,700 --> 00:16:46,850 So, now if I hit run and I add a new item to our to-do list, and I hit add item, then it reloads the text field 172 173 00:16:47,140 --> 00:16:52,030 takeing account the new array, and now it populates my table view. 173 174 00:16:52,040 --> 00:16:55,140 So in this lesson, we looked at a couple of things. 174 175 00:16:55,340 --> 00:16:58,950 We added a new bar button item. 175 176 00:16:58,970 --> 00:17:01,040 We created an IBAction. 176 177 00:17:01,040 --> 00:17:05,240 We created an alert that has an action as well as a text field. 177 178 00:17:05,330 --> 00:17:09,300 And once the user clicks the Add item button in our alert, 178 179 00:17:09,350 --> 00:17:15,380 then we add whatever they wrote in the text field to our itemArray, and then we reload the table view 179 180 00:17:15,410 --> 00:17:17,330 to show that data. 180 181 00:17:17,390 --> 00:17:22,910 So in the next lesson, we're going to be getting on to our main topic: Data 181 182 00:17:22,910 --> 00:17:24,340 Persistence, 182 183 00:17:24,410 --> 00:17:27,180 what can we do to persist the data. 183 184 00:17:27,200 --> 00:17:32,350 I'm going to show you the problem that we currently have that we're not yet aware of, but you're going 184 185 00:17:32,350 --> 00:17:33,470 to see it very soon. 185 186 00:17:33,680 --> 00:17:39,800 And then I'm going to show you one of the easiest ways of persisting data. So all of that and more on 186 187 00:17:39,800 --> 00:17:40,490 the next lesson.