0
1
00:00:00,360 --> 00:00:04,160
Hey, guys. In this lesson, we're gonna be talking about the UITableView
1

2
00:00:04,160 --> 00:00:11,400
which you see pretty much all across iOS and it's one of the bread and butter skills
2

3
00:00:11,430 --> 00:00:14,340
that any iOS developer need to have.
3

4
00:00:14,340 --> 00:00:18,650
So how do we create such a nice scrollable table view?
4

5
00:00:18,660 --> 00:00:23,270
Well, you get started by adding it from the object library, of course.
5

6
00:00:23,310 --> 00:00:32,250
So if you search in here for table view, then you'll be to find this component, and you can drag it onto
6

7
00:00:32,250 --> 00:00:32,870
a screen.
7

8
00:00:32,880 --> 00:00:40,350
So let me just create a new dummy screen. So let's search for a view controller. And go ahead and drop
8

9
00:00:40,350 --> 00:00:41,370
that there.
9

10
00:00:41,550 --> 00:00:48,810
And if I wanted part of it to be covered with a table view, then I could select this table view component,
10

11
00:00:49,200 --> 00:00:55,900
drop it on here. And just as what we've done with that image views or other types of views, we're just gonna
11

12
00:00:55,920 --> 00:00:59,850
put it onto the screen in these sort of dimensions that we want.
12

13
00:00:59,970 --> 00:01:04,040
So in this case, I only want half the screen to be covered by a table view.
13

14
00:01:04,080 --> 00:01:09,210
Now, the other key component of a table view is a table view cell.
14

15
00:01:09,210 --> 00:01:14,590
And even though we only have one cell, it's actually what's called a prototype cell.
15

16
00:01:14,670 --> 00:01:21,120
So it's a cell that's going to be reused lots and lots of times in order to populate every single cell
16

17
00:01:21,120 --> 00:01:22,490
in the table view.
17

18
00:01:22,590 --> 00:01:28,260
So notice if you look in your mail app, every single one of these cells are structured pretty much the
18

19
00:01:28,260 --> 00:01:28,650
same.
19

20
00:01:28,650 --> 00:01:30,650
They have a title that's in bold.
20

21
00:01:30,750 --> 00:01:36,630
They have a subtitle which is the body of the message, and then they've got a disclosure indicator on
21

22
00:01:36,630 --> 00:01:42,110
the right as well as a little bit of gray text here indicating when the message was sent.
22

23
00:01:42,690 --> 00:01:45,960
And then here they've got the capability of a little blue dot.
23

24
00:01:45,960 --> 00:01:52,940
So, essentially, all of these cells are identical other than what's gone into each of these fields.
24

25
00:01:52,940 --> 00:01:56,080
And that's created from these prototype cells.
25

26
00:01:56,330 --> 00:02:04,760
So you can, for example, add a disclosure indicator to all of the cells, or you could make it not selectable,
26

27
00:02:04,790 --> 00:02:12,230
or blue selection, grey selection, you can change the style of it so that it has a title and subtitle,
27

28
00:02:12,620 --> 00:02:18,590
or you can have it with a right detail, left detail, but I'm actually going to keep it as the original
28

29
00:02:18,590 --> 00:02:25,490
which is the custom cell. And I'm going to get rid of that disclosure indicator. But what's really important
29

30
00:02:25,490 --> 00:02:29,420
when you create a prototype cell is to give it an identifier.
30

31
00:02:29,420 --> 00:02:36,710
This is the identify that we're going to be using inside our code to identify which cell we want displayed
31

32
00:02:36,860 --> 00:02:38,290
in our table view.
32

33
00:02:38,330 --> 00:02:44,960
So notice how in the presetup ChatViewController, we've already got an identifier called ReusableCell.
33

34
00:02:44,960 --> 00:02:52,970
And if you look inside the Constants.swift, you also have a type property code cellIdentifier
34

35
00:02:53,660 --> 00:02:56,030
which is set to equal that string.
35

36
00:02:56,030 --> 00:02:58,100
So they should be the same.
36

37
00:02:58,280 --> 00:03:05,900
Now, notice how when you look inside the Object library, there's also such a thing as a Table View Controller.
37

38
00:03:06,230 --> 00:03:13,370
And this is sort of a more specialized view controller namely one that can only really show a table
38

39
00:03:13,370 --> 00:03:14,040
view.
39

40
00:03:14,120 --> 00:03:21,200
So I tend to prefer the flexibility of a normal view controller and I can put in a table view to either
40

41
00:03:21,200 --> 00:03:27,110
cover the entire screen or part of the screen or however I like to lay it out, but I don't actually enjoy
41

42
00:03:27,110 --> 00:03:31,480
using the Table View Controller too much because it's a little bit more limiting.
42

43
00:03:31,520 --> 00:03:36,650
So I'm going to delete both of these screens and head back to my previous design that you should all
43

44
00:03:36,650 --> 00:03:37,280
have.
44

45
00:03:37,520 --> 00:03:44,660
And we're going to get started putting some content into our table view. And the first step is to create
45

46
00:03:44,720 --> 00:03:45,890
a model.
46

47
00:03:45,950 --> 00:03:49,810
So we're going to be creating a model for our messages.
47

48
00:03:49,910 --> 00:03:55,770
So we're gonna be selecting a iOS Swift File and this is going to be called a Message,
48

49
00:03:55,790 --> 00:03:56,710
so singular,
49

50
00:03:57,380 --> 00:04:06,050
and go ahead and click Create. Now, the Message.swift file is going to contain a struct code Message,
50

51
00:04:06,090 --> 00:04:07,670
so exactly the same.
51

52
00:04:07,830 --> 00:04:13,140
And inside here where we've got the field's placeholder, I'm going to replace it with the properties
52

53
00:04:13,140 --> 00:04:15,210
that every method should have.
53

54
00:04:15,210 --> 00:04:17,170
One is a sender.
54

55
00:04:17,190 --> 00:04:24,510
So this is going to be a string data type because it's going to contain the email address of the person
55

56
00:04:24,510 --> 00:04:25,920
who sent the message.
56

57
00:04:25,920 --> 00:04:32,000
So, for example, it'll be 1@2.com or one of the other uses that I've registered.
57

58
00:04:32,100 --> 00:04:37,860
And the second property is going to be something called body, which is going to contain the body of the
58

59
00:04:37,860 --> 00:04:38,640
message,
59

60
00:04:38,730 --> 00:04:41,510
and this, of course, also should be a string.
60

61
00:04:41,790 --> 00:04:42,660
So that's it.
61

62
00:04:42,660 --> 00:04:49,950
We've created our message structure which is going to be the model for creating messages from now on.
62

63
00:04:49,950 --> 00:04:56,220
So if we head back into our ChatViewController, at the very top just below the IBOutlets, I'm going
63

64
00:04:56,220 --> 00:05:04,440
to create a new variable which is going to be called messages. And this is going to contain an array
64

65
00:05:04,560 --> 00:05:07,010
of message objects.
65

66
00:05:07,080 --> 00:05:13,860
So let's go ahead and set that to equal a new array. And inside this array, I'm going to populate it with
66

67
00:05:13,860 --> 00:05:16,170
just three messages to begin with.
67

68
00:05:16,770 --> 00:05:22,770
So the sender for the first one is going to be 1@2.com. And the body of the first message
68

69
00:05:22,860 --> 00:05:30,560
is just going to be "Hey!!" Now, I'm going to add a comma to separate the first item from the rest of them.
69

70
00:05:30,580 --> 00:05:34,890
Now, I'm going to populate it with two more messages that I've written already,
70

71
00:05:34,960 --> 00:05:40,970
so you don't have to watch me type. But, essentially, we've got two senders here, 1@2.com.
71

72
00:05:40,960 --> 00:05:42,840
who's talking to a@b.com.
72

73
00:05:42,880 --> 00:05:47,420
And the 1@2 said, "Hey!" and then got the reply of "Hello!" and then said "What's up.?"
73

74
00:05:47,740 --> 00:05:55,750
So that's all we've got, three items in our messages array which has a data type of Message which is
74

75
00:05:55,870 --> 00:06:02,130
the data type that we've used to structure our messages so they can have a sender and a body.
75

76
00:06:02,170 --> 00:06:06,040
So how do we get these displayed in our table view?
76

77
00:06:06,250 --> 00:06:10,480
Notice how I've already linked up the tableView as an IBOutlet.
77

78
00:06:10,720 --> 00:06:16,960
And if you need to do this in the future when you're creating your own table views, then it's done exactly
78

79
00:06:16,960 --> 00:06:22,720
the same way as you've done before where you simply select the table view, either in the document outline
79

80
00:06:23,170 --> 00:06:28,660
or in the Interface Builder, hold down control and drag, and then you'll end up creating an Outlet.
80

81
00:06:29,410 --> 00:06:35,650
So this Outlet is connected to our tableView and the ChatViewController and its name is tableView.
81

82
00:06:36,970 --> 00:06:42,640
So, now we can access this tableView and we can populate it with some data.
82

83
00:06:43,210 --> 00:06:48,820
The way that you populate data in a tableView is slightly different from how you might imagine it to
83

84
00:06:48,820 --> 00:06:49,410
be.
84

85
00:06:49,450 --> 00:06:54,980
So you might think that somewhere in viewDidLoad or somewhere else, you might say a tableView.cell,
85

86
00:06:55,000 --> 00:07:00,010
et cetera, but actually it works with delegation.
86

87
00:07:00,010 --> 00:07:06,820
Let's scroll down to the very bottom of our file and outside of our existing ChatViewController,
87

88
00:07:06,820 --> 00:07:13,870
let's create an extension, and we're going to extend our ChatViewController so that it can adapt the 
88

89
00:07:13,870 --> 00:07:16,600
UITableViewDataSource protocol.
89

90
00:07:16,690 --> 00:07:23,890
So that means that when our tableView loads up, it's going to make a request for data. and in 
90

91
00:07:23,890 --> 00:07:24,820
our viewDidLoad,
91

92
00:07:24,820 --> 00:07:30,610
we're going to say that the tableView's data source is going to be set as "self."
92

93
00:07:30,610 --> 00:07:37,180
So it's going to look to our ChatViewController and trigger the delegate methods in order to get the
93

94
00:07:37,180 --> 00:07:38,740
data that it needs.
94

95
00:07:38,740 --> 00:07:45,250
That's why down here, we've got some methods that are required in order to conform to this protocol.
95

96
00:07:45,250 --> 00:07:51,040
So let's click Fix so that it will automatically insert the methods that we need.
96

97
00:07:51,040 --> 00:07:55,100
The first one is table View numberOfRoseInSection,
97

98
00:07:55,240 --> 00:08:00,430
so how many rows or how many cells do you want in your tableView.
98

99
00:08:00,520 --> 00:08:02,830
And it expects a output.
99

100
00:08:02,980 --> 00:08:09,700
So you have to return an integer in this delegate method and that integer will be used by the tableView
100

101
00:08:09,700 --> 00:08:15,090
to allocate the required number of cells or number of rows.
101

102
00:08:15,430 --> 00:08:23,020
In our case. we know that we've only got three messages, so you could simply return three. But this is
102

103
00:08:23,020 --> 00:08:29,960
pretty bad because it's hardcoded. And in the future, when we have new messages, it's not going to adapt.
103

104
00:08:30,010 --> 00:08:38,190
So let's change this instead to use the messages array and use the count property to return a number
104

105
00:08:38,200 --> 00:08:43,670
dynamically depending on how many messages there are in this array.
105

106
00:08:43,870 --> 00:08:51,640
So that's the first delegate method tackled. The next one is tableView cellForRowAt indexPath.
106

107
00:08:51,970 --> 00:08:54,870
So the indexPath is the position.
107

108
00:08:54,910 --> 00:09:03,670
So, essentially, this method is asking us for a UITableViewCell that it should display in each and
108

109
00:09:03,700 --> 00:09:07,010
every row of our table view.
109

110
00:09:07,030 --> 00:09:12,870
So here we have to create a cell and return it to the tableView.
110

111
00:09:12,970 --> 00:09:14,560
So let's do that now.
111

112
00:09:14,740 --> 00:09:23,830
Let's create a cell and we're going to set it to = tableView.dequeueReusableCell withIdentifier
112

113
00:09:23,890 --> 00:09:25,150
for index.
113

114
00:09:25,150 --> 00:09:34,000
So what this does is it returns a reusable cell object for the specified reuse identifier and adds it
114

115
00:09:34,090 --> 00:09:35,470
to the table.
115

116
00:09:35,470 --> 00:09:38,620
So what is the reuse identifier?
116

117
00:09:38,830 --> 00:09:44,100
Well, that, remember is what we set in our table view prototype cell.
117

118
00:09:44,110 --> 00:09:49,990
So if you select the ReusableCell and you go to the Attribute Inspector, you should see it right here.
118

119
00:09:50,500 --> 00:09:57,940
And I've also included that in the constants. So we can access it simply by accessing our struct K
119

120
00:09:57,940 --> 00:09:59,830
cellIdentifier.
120

121
00:09:59,830 --> 00:10:04,660
Let's do that right here K.cellIdentifier
121

122
00:10:04,870 --> 00:10:07,710
and that will be our cell's identifier.
122

123
00:10:07,900 --> 00:10:14,340
And then the index path is simply the current one that the tableView is requesting some data for.
123

124
00:10:14,350 --> 00:10:19,300
So this method is going to get called for as many rows as you have in your tableView.
124

125
00:10:19,330 --> 00:10:23,550
So currently, our message.count is three.
125

126
00:10:23,560 --> 00:10:31,270
So this is going to return three which means that this method is gonna be called three times and each
126

127
00:10:31,270 --> 00:10:35,530
time it's asking for a cell for a particular row.
127

128
00:10:35,530 --> 00:10:41,920
Now, let's go ahead and add the indexPath property that came from this delegate method in here, and we've
128

129
00:10:41,920 --> 00:10:46,450
now created a brand-new tableView cell.
129

130
00:10:46,450 --> 00:10:54,460
It's still giving us an error saying that we're missing return in a function expected to output 
130

131
00:10:54,490 --> 00:10:56,160
a UITableViewCell.
131

132
00:10:56,350 --> 00:10:59,600
We will do that eventually, but we're not in a hurry.
132

133
00:10:59,620 --> 00:11:05,000
The next step is I want to give the cell some data, right?
133

134
00:11:05,050 --> 00:11:14,020
So I'm going to tap into that cell and I'm going to edit the textLabel property and that will correspond
134

135
00:11:14,020 --> 00:11:21,750
to the main label in the cell. And then I'm going to tap the text property of this textLabel.
135

136
00:11:21,940 --> 00:11:24,700
And for now, I'm just gonna set it to equal the word
136

137
00:11:24,700 --> 00:11:27,030
"This is a cell."
137

138
00:11:27,370 --> 00:11:31,090
And finally, now I'm ready to return this cell
138

139
00:11:31,330 --> 00:11:35,610
and that is going to be slotted into my tableView.
139

140
00:11:35,680 --> 00:11:36,880
Let's go ahead and give it a spin.
140

141
00:11:40,250 --> 00:11:44,960
So let's log in and you can see we now have three cells.
141

142
00:11:44,960 --> 00:11:51,770
This is a cell, this is a cell, and this is a cell. And we have three of them because of this method and
142

143
00:11:51,770 --> 00:11:54,080
they have a textLabel with the text.
143

144
00:11:54,110 --> 00:11:56,820
This is a cell because of this method.
144

145
00:11:56,870 --> 00:12:04,580
So what if we wanted to say something different in each of the cells? For example, what if we wanted the
145

146
00:12:04,730 --> 00:12:07,570
actual row number to be printed?
146

147
00:12:07,640 --> 00:12:15,020
Well, we can get access to the row number by tapping into this indexPath property. So we can say
147

148
00:12:15,020 --> 00:12:17,860
indexPath.row.
148

149
00:12:17,990 --> 00:12:24,710
And that is going to correspond to the row number that's currently requesting for some cell data.
149

150
00:12:24,790 --> 00:12:31,610
Now, because this is an integer, in order to turn it into a string, I'm going to use the string interpolation
150

151
00:12:31,610 --> 00:12:41,310
method and put it inside some double quotes. So, now let's run our app again. And now you can see that
151

152
00:12:41,310 --> 00:12:45,840
we're getting the row number being inserted as the textLabel's text.
152

153
00:12:46,050 --> 00:12:50,580
The first row is row 0, then row 1, then row two.
153

154
00:12:50,610 --> 00:12:59,400
So how can we use this indexPath. row in order to pull out the body of the message from our messages
154

155
00:12:59,400 --> 00:12:59,820
array?
155

156
00:13:00,120 --> 00:13:02,330
Well, that should be pretty simple.
156

157
00:13:02,370 --> 00:13:12,180
All we need to do is to take our indexPath.row and put it inside a set of square brackets to subscript
157

158
00:13:12,450 --> 00:13:16,810
our messages array with this number.
158

159
00:13:16,830 --> 00:13:23,520
So that means when the tableView is requesting the data for the 0 row, then this is going to be equal
159

160
00:13:23,520 --> 00:13:24,180
to zero,
160

161
00:13:24,540 --> 00:13:28,800
and it's going to pull out the message at position 0.
161

162
00:13:28,800 --> 00:13:33,860
So this one. But this is not enough because this currently has type message.
162

163
00:13:33,900 --> 00:13:40,380
Instead, we actually want the body property out of this message to be put into the cell's textLabel,
163

164
00:13:40,380 --> 00:13:41,220
right?
164

165
00:13:41,250 --> 00:13:49,160
So, now let's run our app. And you can see we've now got all the messages that came from our messages
165

166
00:13:49,160 --> 00:13:56,900
array being populated in each of these cells. Now, you might be wondering, hey, this looks a little bit
166

167
00:13:56,900 --> 00:13:59,360
different from what I've seen in mail.
167

168
00:13:59,360 --> 00:14:01,220
Where are the separators?
168

169
00:14:01,220 --> 00:14:07,220
Well, we can actually go into our storyboard and set a setting on the tableView.
169

170
00:14:07,730 --> 00:14:14,060
So if you go into the Attribute Inspector and you take a look at the Separator property, I've actually
170

171
00:14:14,060 --> 00:14:20,600
said it to None. But you can, of course, set it back to default which gives you that separator that you're
171

172
00:14:20,600 --> 00:14:25,390
probably familiar with from the mail app like so.
172

173
00:14:26,030 --> 00:14:29,270
But in terms of our messaging app, it doesn't really make sense.
173

174
00:14:29,270 --> 00:14:35,780
So I'm going to set that back to None, so that we have our messages showing up later on in speech bubbles
174

175
00:14:35,840 --> 00:14:38,460
without the separators.
175

176
00:14:38,680 --> 00:14:45,880
Now, the final thing I want to show you about tableViews is that in addition to a TableViewDataSource,
176

177
00:14:46,240 --> 00:14:49,870
they also have a protocol called the tableViewDelegate.
177

178
00:14:49,900 --> 00:14:57,040
Now, the difference here is that the data source is the protocol that's responsible for populating the
178

179
00:14:57,040 --> 00:14:57,740
tableView,
179

180
00:14:57,910 --> 00:15:04,570
so telling it how many cells it needs and which cells that put into the tableView. But we can also create
180

181
00:15:04,570 --> 00:15:13,840
an extension for our ChatViewController that has the UITableViewdelegate's protocol adopted.
181

182
00:15:13,840 --> 00:15:21,040
And in order to use this, we, of course, have to go back up to our viewDidLoad, take our tableView IBOutlets
182

183
00:15:21,100 --> 00:15:27,430
which is linked to the table View in our Interface Builder and set its delegate to "self."
183

184
00:15:28,180 --> 00:15:34,030
Now, what'll happen is whenever the tableView is interacted with by the user,
184

185
00:15:34,030 --> 00:15:40,840
say, for example, if a particular row in the tableView was selected, then we're going to get this method
185

186
00:15:40,840 --> 00:15:47,350
triggered in our ChatViewController because we've set this current class as the delegate.
186

187
00:15:47,350 --> 00:15:50,600
So let's go ahead and print the indexPath.row
187

188
00:15:50,620 --> 00:15:54,610
of the tableView that we're selected.
188

189
00:15:54,610 --> 00:16:02,020
So let's go ahead and hit run. And what we're expecting is that when I tap or when I click in the simulator
189

190
00:16:02,470 --> 00:16:08,800
on one of the cells, then it's going to print the indexPath of the cell that was tapped on.
190

191
00:16:08,800 --> 00:16:10,570
So this should be cell zero.
191

192
00:16:10,570 --> 00:16:13,270
So let's click that and we get zero.
192

193
00:16:13,270 --> 00:16:14,730
This should be cell 2.
193

194
00:16:14,740 --> 00:16:17,190
So we get 2 and this should be 1.
194

195
00:16:17,230 --> 00:16:23,800
So, now that means that we can receive messages from the tableView when the user interacts with our
195

196
00:16:23,800 --> 00:16:30,030
tableView and we'll get to know which cell they interacted with so that we can do things, for example,
196

197
00:16:30,040 --> 00:16:36,460
so if we had a to do list, then we might check each item off, and we might change these cells, et cetera. 
197

198
00:16:36,520 --> 00:16:42,890
But in our messaging app, we actually don't want the user to be able to interact with each of these cells.
198

199
00:16:42,940 --> 00:16:49,240
So I'm actually going to go ahead and delete all of this code here as well as setting the delegate down
199

200
00:16:49,240 --> 00:16:56,860
here. And the other thing I'm gonna do is I'm going to go into my Main.storyboard, select that prototype
200

201
00:16:56,860 --> 00:17:01,900
cell, and change these selection property to None.
201

202
00:17:02,380 --> 00:17:10,720
So this way, when the user taps on each of those cells, instead of turning grey, but doing nothing. 
202

203
00:17:10,810 --> 00:17:14,640
It's actually now going to not allow any sort of interaction.
203

204
00:17:14,650 --> 00:17:21,310
So when you click on it, nothing happens, which is kind of the normal behavior of a chat message.
204

205
00:17:21,310 --> 00:17:22,330
So that's it.
205

206
00:17:22,330 --> 00:17:28,990
In this lesson, we learned about the UITableView and how to set up the UITableViewDataSource protocol,
206

207
00:17:29,320 --> 00:17:36,130
as well as the UITableViewDelegate protocol. In the next lesson, instead of having these plain old
207

208
00:17:36,130 --> 00:17:42,250
messages and the bog-standard table view cells, we're going to jazz it up and we're going to create some
208

209
00:17:42,250 --> 00:17:48,130
custom UI views to put in here, and we're going to create some message bubbles.
209

210
00:17:48,130 --> 00:17:51,610
So all of that and more, I'll see you on the next lesson.
