This guide is made for beginners to learn the foundations of the UITableView class programmatically with auto layout in Swift.
How to create a table view programmatically?
Let's jump straight into the coding part, but first: start Xcode, create a new iOS single view app project, enter some name & details for the project as usual, use Swift and finally open the
ViewController.swift file right away. Now grab your keyboard! ⌨️
Pro tip: use Cmd+Shift+O to quickly jump between files
I'm not going to use interface builder in this tutorial, so how do we create views programmatically? There is a method called
loadView that's where you should add custom views to your view hierarchy. You can option+click the method name in Xcode & read the discussion about loadView method, but let me summarize the whole thing.
We'll use a weak property to hold a reference to our table view. Next, we override the loadView method & call super, in order to load the controller's self.view property with a view object (from a nib or a storyboard file if there is one for the controller). After that we assign our brand new view to a local property, turn off system provided layout stuff, and insert our table view into our view hierarchy. Finally we create some real constraints using anchors & save our pointer to our weak property. Easy! 🤪
Always use auto layout anchors to specify view constarints, if you don't know how to use them, check my layout anchors tutorial, it's takes only about 15 minutes to learn this API, and you won't regret it. It's an extremely useful tool for any iOS developer! 😉
You might ask: should I use weak or strong properties for view references? I'd say in most of the cases if you are not overriding
self.view you should use weak! The view hierarchy will hold your custom view through a strong reference, so there is no need for stupid retain cycles & memory leaks. Trust me! 🤥
Ok, we have an empty table view, let's display some cells! In order to fill our table view with real data, we have to conform to the UITableViewDataSource protocol. Through a simple delegate pattern, we can provide various information for the UITableView class, so it'll to know how much sections and rows will be needed, what kind of cells should be displayed for each row, and many more little details.
Another thing is that UITableView is a really efficient class. It'll reuse all the cells that are currently not displayed on the screen, so it'll consume way less memory than a UIScrollView, if you have to deal with hundreds or thousands of items. To support this behavior we have to register our cell class with a reuse identifier, so the underlying system will know what kind of cell is needed for a specific place. ⚙️
After adding a few lines of code to our view controller file, the table view is now able to display a nice list of emojis! We are using the built-in UITableViewCell class from UIKit, which comes really handy if you are good to go with the "iOS-system-like" cell designs. We also conformed to the data source protocol, by telling how many items are in our section (currently there is only one section), and we configured our cell inside the famous cell for row at indexPath delegate method. 😎
Customizing table view cells
UITableViewCell can provide some basic elements to display data (title, detail, image in different styles), but usually you'll need custom designed cells. Here is a basic template of a custom cell subclass, I'll explain all the methods after the code.
init(style:reuseIdentifier) method is a great place to override the cell style property if you are going to use the default UITableViewCell programmatically, but with different styles (there is no option to set cellStyle after the cell was initialized). For example if you need a .value1 styled cell, just pass the argument directly to the super call. This way you can benefit from the 4 predefined cell styles.
NOTE: You'll also have to implement
init(coder:), so you should create a common initialize() function where you'll be able to add your custom views ot the view hierarchy, like we did in the
loadView method above. If you are using xib files & IB, you can use the
awakeFromNib method to add extra style to your views through the standard
@IBOutlet properties (or add extra views to the hierarchy as well). 👍
The last method that we have to talk about is
prepareForReuse. As I mentioned before cells are being reused so if you want to reset some properties, like the background of a cell, you can do it here. This method will be called before the cell is going to be reused.
Let's make two new cell subclasses to play around with.
Our custom cell will have a big image background plus a title label in the center of the view with a custom sized system font. Also I've added the Swift logo as an asset to the project, so we can have a nice demo image. 🖼
That's it, let's start using these new cells. I'll even tell you how to set custom height for a given cell, and how to handle cell selection properly, but first we need to get to know with another delegate protocol. 🤝
Basic UITableViewDelegate tutorial
This delegate is responsible for lots of things, but for now we're going to cover just a few interesting aspects, like how to handle cell selection & provide a custom cell height for each items inside the table. Here is a quick sample code.
As you can see I'm registering my brand new custom cell classes in the
viewDidLoad method. I also changed the code inside the
cellForRowAt indexPath method, so we can use the
CustomCell class instead of
UITableViewCells. Don't be afraid of force casting here, if something goes wrong at this point, your app should crash. 🙃
There are two delegate methods that we are using here. In the first one, we have to return a number and the system will use that height for the cells. If you want to use different cell height per row, you can achieve that too by checking indexPath property or anything like that. The second one is the handler for the selection. If someone taps on a cell, this method will be called & you can perform some action.
An indexPath has two interesting properties: section & item (=row)
Multiple sections with headers and footers
It's possible to have multiple sections inside the table view, I won't go too much into the details, because it's pretty straightforward. You just have to use indexPaths in order to get / set / return the proper data for each section & cell.
Although there is one interesting addition in the code snippet above. You can have a custom title for every section, you just have to add the
titleForHeaderInSection data source method. Yep, it looks like shit, but this one is not about U&I/X. 😂
However if you are not satisfied with the layout of the section titles, you can create a custom class & use that instead of the built-in ones. Here is how to do a custom section header view. Here is the implementation of the reusable view:
There is only a few things left to do, you have to register your header view, just like you did it for the cells. It's exactly the same way, except that there is a separate registration "pool" for the header & footer views. Lastly you have to implement two additional, but relatively simple (and familiar) delegate methods.
Footers works exactly the same as headers, you just have to implement the corresponding data source & delegate methods in order to support them.
You can even have multiple cells in the same tableview based on the row or section index or any specific business requirement. I'm not going to demo this here, because I have a way better solution for mixing and reusing cells inside the CoreKit framework. It's already there for table views as well, plus I already covered this idea in my ultimate collection view tutorial post. You should check that too. 🤓
Section titles & indexes
Ok, if your brain is not melted yet, I'll show you two more little things that can be interesting for beginners. The first one is based on two additional data source methods and it's a very pleasant addition for long lists. (I prefer search bars!) 🤯
If you are going to implement these methods above you can have a little index view for your sections in the right side of the table view, so the end-user will be able to quickly jump between sections. Just like in the official contacts app. 📕
Selection vs highlight
Cells are highlighed when you are holding them down with your finger.
Cell is going to be selected if you release your finger from the cell.
Don't overcomplicate this. You just have to implement two methods in you custom cell class to make everything work. I prefer to deselect my cells right away, if they're not for example used by some sort of data picker layout. Here is the code:
As you can see, it's ridiculously easy, but most of the beginners don't know how to do this. Also they usually forget to reset cells before the reusing logic happens, so the list keeps messing up cell states. Don't worry too much about these problems, they'll go away as you're going to be more experienced with the UITableView APIs.
That's it for now, next time I'm going to continue with some advanced table views!