I plan on making a series of posts regarding some patterns I like to use while writing iOS apps ranging from UITableViews and their delegates/datasources, reuse of classes using generics, and navigation flow. Today, I’ll start with UITableViews.
Let’s start with a basic view controller. I’ll write everything out using just code for clarities sake.
I like to abstract out the UITableViewDataSource and UITableViewDelegate into a seperate class for reusability’s and avoiding code repetition.
First, you’ll notice that it’s doubly generic over two types: Provider which is of the type DataProvider and Cell which is a simple UITableViewCell which conforms to ConfigurableCell (from where Cell: ConfigurableCell). I’ll go over ConfigurableCell first.
The protocol ConfigurableCell is quite simple, it just states that the cell that conforms to it must implement a function which is used to configure the cell for it’s display. This function will be the sole function called in cellForRowAtIndexPath. The associatedtype is a placeholder type for which the cell is designed to be configured to. So, for example, if the data you want to display in your tableView is an Array of Books, your configure function would be
Next, we have the DataProvider type. This is quite simple. This is just a protocol the holder of the objects you want to display conform to.
The purpose of this class is obviously to fill out the reqruied UITableViewDataSource methods. Further extension of this protocol can provide further functionality such as insertion/removal/append/etc. But we’ll keep it simple here.
A typical type I make is ArrayProvider:
Now, we move back to the DataSource:
Now, the purpose of the DataSource becomes rather clear. You feed it a UITableView and a DataProvider and it handles all the connections. It’s reusable and isolated from the rest of your code. Any further modification can be handled in a variety of ways, but the repetitive boiler plate is isolated and regularized.
A useful subclass I create is a DataProvider tailored to the aforementioned ArrayProvider.
This subclass simply provides an initializer for when your objects are contained in an array so you can use the ArrayProvider type. To be honest, I’d prefer this be a part of the original DataSource class, but Swift’s type system doesn’t allow recursive constraints, yet, and that would be a requirement to write an extension where the where clauses imply recursion. So I simply subclass, for now. (This is a problem I’m running into exceedingly often the more and more I try to use generic code.)
Now, we can finally set up our view controller.
And your UITableView is fully configured with that little amount of code in your view controller. This clearly helps with MassiveViewController syndrome, even if it merely hides the code else where. But it does allow for extremely efficient reusability and customization. Lets say you want to make another view controller to show information about the authors. This is the entirety of the code you have to add:
And that’s it! With various other subclasses/protocols added in, code reuse can be further expanded upon. A further step is to make the UIViewController itself generic. Though, I have to admit, maximizing code reuse can be an addiction that sometimes Swift’s compiler can’t keep up with. I’ve noticed a few times that extensively generic view controllers utilizing generic properties can causes it to fail without any error in the code. But hopefully that’s all fixed by the time Swift 4 comes out, though I’m not getting my hopes too high.
I also want to note that my biggest reference for this post was Objc.io’s Core Data book. It introduced me to some of these patterns. I’ve since moved onto using Realm for all my local storage purposes, but that book had some really fascinating Swift code.