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.