0
1
00:00:00,180 --> 00:00:00,480
All right.
1

2
00:00:00,510 --> 00:00:06,090
So now that we've seen the awesomeness of dark mode as well as vector image assets, it's time to move
2

3
00:00:06,090 --> 00:00:11,640
on to the next thing which is learning how to use the UITextField.
3

4
00:00:11,640 --> 00:00:16,010
Let's take a closer look at our text field in the Interface Builder.
4

5
00:00:16,020 --> 00:00:24,030
Notice how we've got a text field right here which you can find from the object library. And it's right
5

6
00:00:24,030 --> 00:00:24,990
here.
6

7
00:00:24,990 --> 00:00:33,390
The text field is going to allow the user to use the keyboard on the iPhone and type in an input.
7

8
00:00:33,390 --> 00:00:40,590
By default Apple's UITextField already knows how to handle light and dark modes, so that the color
8

9
00:00:40,590 --> 00:00:44,370
of the tags depending on which mode we're in will be different.
9

10
00:00:44,370 --> 00:00:51,840
So it will be white in dark mode and it will black in light mode, and the background color also adjusts depending
10

11
00:00:51,840 --> 00:00:54,300
on the interface style.
11

12
00:00:54,560 --> 00:01:01,990
Now, we can also set the type of keyboard that we want by changing these text input traits.
12

13
00:01:02,030 --> 00:01:10,400
So for example, we could say that the capitalization for our inputs should be for each word because our
13

14
00:01:10,400 --> 00:01:13,540
users are going to be typing in the names of cities.
14

15
00:01:13,550 --> 00:01:20,120
So for example, this means that if they start typing the word "London," then it will automatically capitalize
15

16
00:01:20,120 --> 00:01:28,800
the "L" here. And we've also got other things, such as the type of keyboard, so you can change the keyboard
16

17
00:01:28,800 --> 00:01:37,140
that pops up to a number pad or one that is for e-mail addresses or Twitter. And we can also change what's
17

18
00:01:37,140 --> 00:01:38,240
in the return key.
18

19
00:01:38,430 --> 00:01:42,800
So the Default just says return, and you should be familiar with that
19

20
00:01:42,810 --> 00:01:48,900
if you use the iPhone keyboard often. But I'm going to change it to Go because it seems to make more
20

21
00:01:48,900 --> 00:01:52,260
sense when we are searching for the weather in a city.
21

22
00:01:52,260 --> 00:01:57,970
And finally, I want to show you that you can also change the text to be Secure Text Entry.
22

23
00:01:58,020 --> 00:02:03,810
So what this means is that when you have some text that is for a password field, you don't actually see
23

24
00:02:03,810 --> 00:02:08,790
the actual text, so that somebody who's looking over your user's shoulders, won't be able to know what
24

25
00:02:08,790 --> 00:02:10,850
their password is.
25

26
00:02:10,890 --> 00:02:11,220
All right.
26

27
00:02:11,250 --> 00:02:15,990
So now that we've seen this text field, let's go ahead and set it up.
27

28
00:02:15,990 --> 00:02:21,550
So I've left all of this for you to do, so you can see how to set up a UItTextField from scratch.
28

29
00:02:21,600 --> 00:02:28,050
Now, let's go ahead and control-click to create a new IBOutlet which I'm going to call the searchTextField,
29

30
00:02:28,050 --> 00:02:39,720
and then I'm going to add a IBAction from this search button to say searchPressed, and then change
30

31
00:02:39,720 --> 00:02:42,290
the data type to a UIButton.
31

32
00:02:42,360 --> 00:02:49,410
And now I can tap into this IPBAction and see what the user's typed in the search field.
32

33
00:02:49,410 --> 00:02:55,290
So the idea here is that the user would tap on this field, type in the name of the city, and then press the
33

34
00:02:55,350 --> 00:02:59,090
search button at which point, we'll be able to see what they typed.
34

35
00:02:59,100 --> 00:03:06,000
So as you might guess, the text field has some pretty common properties like the one that we saw earlier
35

36
00:03:06,360 --> 00:03:09,990
when we were setting it in the Main.storyboard.
36

37
00:03:09,990 --> 00:03:16,330
So if you select the text field, you can see it's got a text property like a label, but this corresponds
37

38
00:03:16,330 --> 00:03:19,500
to the text that the user has typed inside here.
38

39
00:03:20,040 --> 00:03:27,000
So we can get a hold of it by tapping into the searchTextField.text property which, again, corresponds
39

40
00:03:27,000 --> 00:03:29,970
to the text displayed by the text field.
40

41
00:03:29,970 --> 00:03:35,400
Now, that's different from the text that you see here in sort of a light color.
41

42
00:03:35,400 --> 00:03:37,660
That is the placeholder text.
42

43
00:03:37,760 --> 00:03:40,920
And this is kind of meant to be like the reminder for the user.
43

44
00:03:40,980 --> 00:03:46,320
This is what you should type into this text field like it might say "Password" if it was in the password
44

45
00:03:46,320 --> 00:03:53,480
field, or it might say "Enter a city name" if it's in this particular field. But it's kind of up to you.
45

46
00:03:53,490 --> 00:03:57,360
But I think search seems to make sense for me.
46

47
00:03:57,360 --> 00:04:01,230
This is where you're going to search for a city name.
47

48
00:04:01,410 --> 00:04:07,870
And now we can go ahead and try to print what's inside our searchField.text. 
48

49
00:04:08,010 --> 00:04:16,430
So because the text property is a optional string because it doesn't have to be set,
49

50
00:04:16,430 --> 00:04:18,850
it could also just be an empty string,
50

51
00:04:18,980 --> 00:04:23,810
and, in fact, it tells you that the string is empty by default.
51

52
00:04:23,810 --> 00:04:29,960
So we can go ahead and unwrap that if we want to print it without that little yellow warning because
52

53
00:04:29,960 --> 00:04:31,400
we know that it's an optional,
53

54
00:04:31,400 --> 00:04:35,450
and we know that we're going to type something into it when we print it to see its value.
54

55
00:04:35,900 --> 00:04:43,410
So let's go ahead and run the app and see what we get. So when our app runs and you click in the search
55

56
00:04:43,410 --> 00:04:50,670
field, it should bring up the soft keyboard, so the keyboard that's attached to the iPhone. If it doesn't
56

57
00:04:50,670 --> 00:04:58,470
bring it up, then you can go into the Hardware menu for the simulator, and go to Keyboard and Toggle Software
57

58
00:04:58,500 --> 00:05:02,070
Keyboard, or just use the shortcut of command K.
58

59
00:05:02,310 --> 00:05:06,500
And that should hide or bring back the soft keyboard.
59

60
00:05:06,510 --> 00:05:12,660
`Now when I start typing in here, you'll notice that we've currently got our Secure Text Entry selected,
60

61
00:05:13,080 --> 00:05:19,960
and we've also managed to change the return key from the default which says return to go.
61

62
00:05:20,010 --> 00:05:27,390
So I'm gonna go ahead and uncheck that Secure Text Entry. So I can see my words being capitalized even
62

63
00:05:27,390 --> 00:05:35,150
without me hitting shift. Now that we've seen all keyboard in action, let's go ahead and click on the
63

64
00:05:35,150 --> 00:05:42,050
search button, and you should be able to see the words that you've typed in their printed down here.
64

65
00:05:43,210 --> 00:05:49,090
That is because we're tapping into these searchTextField IBOutlet and then getting its text property
65

66
00:05:49,360 --> 00:05:49,990
printed.
66

67
00:05:50,950 --> 00:06:00,160
But you'll notice that when I type a word in here, let's say,  "London," and click on the go button,
67

68
00:06:00,160 --> 00:06:06,790
nothing actually happens, even though you would expect that it would have the same behavior as our search
68

69
00:06:06,790 --> 00:06:07,510
button.
69

70
00:06:07,510 --> 00:06:10,570
So how do we tap into that go button?
70

71
00:06:10,570 --> 00:06:14,130
Well, it's a little bit different from what you might expect.
71

72
00:06:14,140 --> 00:06:22,240
We can't simply just create an IBOutlet to the keyboard and get a hold of when the keyboard go button
72

73
00:06:22,240 --> 00:06:23,370
gets pressed.
73

74
00:06:23,470 --> 00:06:32,050
Instead, we have to use something called a UITextFieldDelegate. So the first thing we need to do is
74

75
00:06:32,050 --> 00:06:41,410
we need to add a comma after the UIViewController and type UITextFieldDelegate.
75

76
00:06:41,410 --> 00:06:49,240
And this will allow our class, our weather view controller, to manage the editing and validation of text
76

77
00:06:49,330 --> 00:06:50,890
in a text field.
77

78
00:06:50,950 --> 00:06:56,800
So let's hit enter to add that. The next step is inside our viewDidLoad.
78

79
00:06:56,800 --> 00:07:04,030
I'm going to delete the comment there, but I'm going to tap into that searchTextField and tap into
79

80
00:07:04,030 --> 00:07:12,430
the delegate property to set it as this current class which is, of course, accessed using that "self"
80

81
00:07:12,430 --> 00:07:20,050
keyword. Here what this line of code is saying is the text field should report back to our view controller.
81

82
00:07:20,650 --> 00:07:27,400
For example, our text field will handle the task of our user entering text. When the user interacts with
82

83
00:07:27,400 --> 00:07:28,280
our text field,
83

84
00:07:28,280 --> 00:07:35,030
say, your user type something, then or text field will notify our view controller on what's happening.
84

85
00:07:35,380 --> 00:07:37,640
The text field will say something like,
85

86
00:07:37,690 --> 00:07:38,720
"Hey, view controller, 
86

87
00:07:38,920 --> 00:07:45,250
the user just started typing," or the text field will say something like, "Oye, view controller,
87

88
00:07:45,250 --> 00:07:47,440
the user just stopped typing,"
88

89
00:07:47,440 --> 00:07:53,500
or it might even say something like, "Yo, view controller, the user just try to tap elsewhere, should I
89

90
00:07:53,500 --> 00:07:55,560
let them deselect me?"
90

91
00:07:55,600 --> 00:08:01,030
The idea here is that the text field can communicate what's going on. And the way we ensure that the view
91

92
00:08:01,030 --> 00:08:07,060
controllers notified by the text field is by setting the view controller as the delegate.
92

93
00:08:07,060 --> 00:08:10,270
Remember that "self" refers to the current view controller.
93

94
00:08:11,500 --> 00:08:20,650
So what this allows us to do these two steps is we can now create a method called
94

95
00:08:20,800 --> 00:08:26,560
textFieldShouldReturn. And this will ask the delegate which is this current class
95

96
00:08:26,710 --> 00:08:32,150
if the text field should process the pressing of the return button.
96

97
00:08:32,410 --> 00:08:38,840
In other words, the text field will say, "Hey, view controller, the user pressed the return key in the keyboard."
97

98
00:08:38,950 --> 00:08:40,500
What should we do?
98

99
00:08:40,570 --> 00:08:46,690
This is going to be the exact time point when the return button gets pressed and I get to write some
99

100
00:08:46,690 --> 00:08:54,130
code to be triggered at this point. But once I'm done writing my code, I also have to return a true or
100

101
00:08:54,130 --> 00:09:00,310
false that tells the text field whether if it should actually process that return.
101

102
00:09:00,310 --> 00:09:06,520
In my case, what I'm gonna do is I'm just going to use this as if I have an IBAction to that return
102

103
00:09:06,520 --> 00:09:15,610
button. And I'm going to print my searchTextField.text and I'm gonna force unwrap it. And finally,
103

104
00:09:15,670 --> 00:09:23,290
we have to return true because this is a function that expects a boolean as an output, so that our text
104

105
00:09:23,290 --> 00:09:26,480
field will be allowed to actually return.
105

106
00:09:26,500 --> 00:09:37,380
So now if we hit run and we type a word into our text field and then go ahead and click on the return
106

107
00:09:37,380 --> 00:09:37,870
button,
107

108
00:09:37,890 --> 00:09:44,640
so this has been renamed go, but this is always known as the return button of the keyboard, then it will
108

109
00:09:44,640 --> 00:09:51,960
trigger this function textFieldShouldReturn and we get the text inside our search field printed down
109

110
00:09:51,960 --> 00:10:01,580
here, and we allow this return process to go through with our return true. So now we can get hold of what
110

111
00:10:01,580 --> 00:10:07,460
the users typed into the text field from two places, either if they've typed in something and then press
111

112
00:10:07,460 --> 00:10:13,040
the search button, or if they've typed something and then press the go button.
112

113
00:10:13,040 --> 00:10:19,370
I know that a lot of people, at least me included, when I'm typing inside the keyboard, it's much quicker
113

114
00:10:19,370 --> 00:10:22,040
for my thumb to reach the go button,
114

115
00:10:22,040 --> 00:10:27,380
and I expect it to basically hit enter, kind of like the return key on a keyboard.
115

116
00:10:27,380 --> 00:10:33,680
So both of these buttons now trigger the same thing which is for me to be able to get hold of what's
116

117
00:10:33,770 --> 00:10:40,520
inside the searchTextField. But there is just one problem at the moment, I can't seem to get rid of
117

118
00:10:40,520 --> 00:10:47,690
this keyboard no matter where I click, or if I click on the search or the go, it doesn't dismiss itself
118

119
00:10:47,720 --> 00:10:48,700
like it should do.
119

120
00:10:48,710 --> 00:10:53,000
It should kind of disappear because I'm saying I'm done with it now.
120

121
00:10:53,210 --> 00:10:56,680
So how can we fix this?
121

122
00:10:56,700 --> 00:11:03,150
Well, we can tell our IBAction searchPressed that in addition to printing the searchFieldText, it
122

123
00:11:03,150 --> 00:11:08,270
should also make our search field and editing.
123

124
00:11:08,400 --> 00:11:15,720
So, if we tap into this method code endEditing and set it to true, then it will tell the search field
124

125
00:11:15,750 --> 00:11:18,870
that we're done with editing and you can dismiss the keyboard.
125

126
00:11:19,380 --> 00:11:25,800
So let's put that in both places, the text field should return as well as the searchPressed.
126

127
00:11:26,370 --> 00:11:35,110
So now when we run our app and I go ahead and type something into my text field and I press the search
127

128
00:11:35,110 --> 00:11:38,550
button, then it dismisses my keyboard.
128

129
00:11:38,560 --> 00:11:43,480
Similarly, if I press the go button, it also dismisses my keyboard.
129

130
00:11:43,480 --> 00:11:52,660
So perfect. Now, what if we wanted to be able to clear what's in the text field to set it back to its
130

131
00:11:52,660 --> 00:11:53,760
original state,
131

132
00:11:53,950 --> 00:12:00,790
Once we click on the go button or the search button because at the moment, it's kind of leaving it in
132

133
00:12:00,790 --> 00:12:06,550
there, even though we said that we're done with editing of the text field and we can dismiss the keyboard.
133

134
00:12:06,550 --> 00:12:09,550
It's kind of weird to leave the text in there.
134

135
00:12:09,550 --> 00:12:16,380
So how can we tap into this moment when the text field has ended editing?
135

136
00:12:16,380 --> 00:12:19,500
Well, there's a delegate method for that.
136

137
00:12:19,600 --> 00:12:26,170
Remember, the delegate is the one who is notified. By being the delegate of the text field, our view controller
137

138
00:12:26,200 --> 00:12:33,360
can be notified when the text field ends editing. Similar to how we got hold of textFieldShouldReturn,
138

139
00:12:33,460 --> 00:12:37,900
we can get hold of a method called textFieldDidEndEditing.
139

140
00:12:37,900 --> 00:12:44,890
This is the equivalent of our text field saying, "Hey, view controller, the user stopped editing." And inside
140

141
00:12:44,950 --> 00:12:51,700
this bracket, the code will be triggered as soon as any of the text fields on the screen are done with
141

142
00:12:51,790 --> 00:12:52,960
editing.
142

143
00:12:52,960 --> 00:13:01,250
So inside here, we can set the searchTextFields.text property to equal a empty string.
143

144
00:13:01,600 --> 00:13:10,250
And when we run this code, you can see that as soon as I'm done with my typing and I press go, it clears
144

145
00:13:10,310 --> 00:13:17,990
my text field so that I can type a new search term the next time, and it works both from my search button
145

146
00:13:18,410 --> 00:13:20,300
as well as from my go button.
146

147
00:13:22,040 --> 00:13:28,140
A nice thing about setting the textField.text property to an empty string using
147

148
00:13:28,170 --> 00:13:31,740
textFieldDidEndEditing is that we avoid a bit of repetition.
148

149
00:13:31,740 --> 00:13:38,070
Otherwise, we would have to do this twice. First, on line 26 after the search button is pressed, and then
149

150
00:13:38,130 --> 00:13:42,730
,again, on line 31 after the return key is pressed.
150

151
00:13:42,820 --> 00:13:50,490
Now, there's one final delegate method that's quite useful and it's called the
151

152
00:13:50,510 --> 00:13:51,660
textFieldShouldEndEditing.
152

153
00:13:51,660 --> 00:13:56,130
So if we type in the textFieldShouldEndEditing,
153

154
00:13:56,130 --> 00:14:01,710
you can see that, again, it expects a boolean as the output.
154

155
00:14:01,710 --> 00:14:07,740
Notice how all the methods that have the word "should" in the name are asking for permission.
155

156
00:14:07,740 --> 00:14:13,200
This is the text field saying, "Excuse me, view controller, the user just tapped elsewhere.
156

157
00:14:13,200 --> 00:14:14,220
What should I do sir?"
157

158
00:14:14,220 --> 00:14:16,600
Should I allow them to stop editing?
158

159
00:14:17,110 --> 00:14:22,920
Here our view controller gets to decide what happens when the user tries to deselect the text field.
159

160
00:14:23,070 --> 00:14:28,340
But wait, why might you want to prevent your user to stop editing a text field?
160

161
00:14:28,350 --> 00:14:30,660
Why trap them in editing mode?
161

162
00:14:30,690 --> 00:14:37,410
Well, the textFieldShouldEndEditing method is actually really useful for doing some validation on
162

163
00:14:37,410 --> 00:14:38,640
what the user typed.
163

164
00:14:39,770 --> 00:14:49,400
So for example, we might want to check to see if the textField.text property is not equal to an
164

165
00:14:49,400 --> 00:14:53,820
empty string because the user should really type something in there.
165

166
00:14:53,900 --> 00:14:59,780
If we're gonna use that text to check for the weather, then we're kind of assuming that they've type
166

167
00:14:59,780 --> 00:15:03,160
something, rather than it being an empty string, right?
167

168
00:15:03,740 --> 00:15:09,500
So in this case, well, then we're going to allow our text field to return. So we're gonna say,
168

169
00:15:09,500 --> 00:15:17,960
"true," it should end editing. But if it's actually equal to an empty string, then we're going to remind
169

170
00:15:18,020 --> 00:15:25,160
or alert the user that they have to write something. And to do that, one of the easiest ways is tapping
170

171
00:15:25,160 --> 00:15:27,710
into the placeholder property.
171

172
00:15:27,710 --> 00:15:35,750
So remember that inside our Main.storyboard, we set our placeholder property to say, "Search," which
172

173
00:15:35,750 --> 00:15:39,200
is what shows up in sort of a light gray color.
173

174
00:15:39,230 --> 00:15:44,720
But in this case, we're going to change the placeholder to something to alert them that they should
174

175
00:15:44,990 --> 00:15:47,210
type something here.
175

176
00:15:47,870 --> 00:15:50,840
And then after that, we're going to return false.
176

177
00:15:50,840 --> 00:15:56,510
We're not going to let the text field and editing yet. We're going to keep the keyboard where it is and
177

178
00:15:56,510 --> 00:16:03,410
we're not going to trigger this method. And you can see that when I click in the text field and I try
178

179
00:16:03,410 --> 00:16:10,580
to click return or click the search button and I haven't typed anything, then it's reminding me to type
179

180
00:16:10,580 --> 00:16:18,220
something in here before it will dismiss the keyboard, end editing, and reset the text field.
180

181
00:16:18,330 --> 00:16:25,740
Now, one thing that I want you to notice here is that notice how in these methods, I've been using that
181

182
00:16:25,800 --> 00:16:33,640
IBOutlet we have created, the search text field which, of course, is a reference to that text field we
182

183
00:16:33,640 --> 00:16:43,240
have in our screen. But down here in this new method, I've actually just referred to a textField.
183

184
00:16:43,240 --> 00:16:46,000
So where does that come from?
184

185
00:16:46,000 --> 00:16:53,350
Well, remember that we are not the ones triggering or calling any of these functions, right?
185

186
00:16:53,470 --> 00:17:00,160
Nowhere in our code do we call text field should return or textFieldShouldEndEditing because they are
186

187
00:17:00,160 --> 00:17:07,810
triggered by the text field. So the text field class is the one that's responsible for calling these
187

188
00:17:07,810 --> 00:17:15,680
methods. And when it calls textFieldShouldEndEditing, when it detects the user dismissing the keyboard,
188

189
00:17:15,730 --> 00:17:23,170
well, then in that moment, it's gonna pass in a reference to the textField that triggered this method.
189

190
00:17:23,620 --> 00:17:30,610
So you could, for example, have a multiple text fields, similar to how in our IBAction, we can get hold of
190

191
00:17:30,610 --> 00:17:39,640
the sender which was the UIButton that actually triggered this IBAction by detecting a touch event.
191

192
00:17:39,640 --> 00:17:48,440
We can have multiple text fields or triggering the same methods. So if we had multiple buttons linked
192

193
00:17:48,500 --> 00:17:53,410
to the same IBAction, then any of those buttons could be the sender.
193

194
00:17:53,420 --> 00:17:56,180
It just depends on who detected the event.
194

195
00:17:56,450 --> 00:18:03,290
And if we have a bountiful text fields, all with their delegates set as this current class, then any of
195

196
00:18:03,290 --> 00:18:09,620
those text fields could be the trigger for these delegate methods, but they will pass their identity
196

197
00:18:09,770 --> 00:18:17,120
in through this text field parameter. So if we don't care about which text field was triggered, then we
197

198
00:18:17,120 --> 00:18:25,670
can simply just use this parameter and apply our validation to any text field in our current view controller
198

199
00:18:25,670 --> 00:18:28,190
using this code.
199

200
00:18:28,420 --> 00:18:34,900
So now that we've implemented our text field, the final thing that we want is no matter if they pressed
200

201
00:18:34,900 --> 00:18:41,140
on the search button or if they pressed on the return or go button, we should be able to get hold of
201

202
00:18:41,140 --> 00:18:48,220
what it is that they wrote which is the textField. text property. And I want to be able to use that
202

203
00:18:48,250 --> 00:18:53,770
which, hopefully, contains the city name to check for the weather in that city.
203

204
00:18:54,040 --> 00:18:59,990
The perfect place to do that is in our textFieldDidEndEditing method.
204

205
00:19:00,280 --> 00:19:08,710
And just before I reset my search text field to empty text, I want to be able to go ahead and use the
205

206
00:19:08,770 --> 00:19:11,870
searchTextField.text.
206

207
00:19:12,250 --> 00:19:21,700
So whatever the user typed in here, "to get the weather for that city," and then and only then do I've reset
207

208
00:19:21,790 --> 00:19:30,370
my searchTextField.text to an empty string. So that functionality would be the next step of building
208

209
00:19:30,370 --> 00:19:36,760
out our weather app. But let's pause for a moment because we've introduced a pretty big topic in this
209

210
00:19:36,760 --> 00:19:42,570
lesson and that's this idea of delegates and protocols.
210

211
00:19:42,640 --> 00:19:49,210
So notice how this UITextField delegate is not a class, it's not a struct, but it's something called
211

212
00:19:49,330 --> 00:19:50,820
a protocol.
212

213
00:19:50,950 --> 00:19:57,400
And to understand what protocols are and why they're so useful, head over to the next lesson where we're
213

214
00:19:57,390 --> 00:20:02,470
going to do a Swift Deep Dive on protocols and extensions.
214

215
00:20:02,710 --> 00:20:05,260
So for all of that and more, I'll see you there.
