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