Taming the Massive Controllers in iOS Part 3

Welcome to the final part of “Taming the Massive Controllers in iOS”. It is highly recommended that you read Part 1 and Part 2 of this series before continuing with this article.

In the previous articles we extracted out the data source of the UITableView control into a separate class called “ShoppingListDataSource”. This moved all the data source functionality out of the ShoppingListViewController into the designated classes for data sources. This technique helped us greatly to reduce the size of the controller and put things in the correct place.

When the user selects a shopping list, he/she is sent to the grocery items screen where all the associated items are displayed of the selected shopping list. This means we need to create a separate data source for the grocery items. The GroceryItemsDataSource will look exactly like the ShoppingListDataSource, the only difference would be that the GroceryItemsDataSource will be working on the items of type GroceryItem instead of ShoppingList as shown in the screenshot below:

GroceryItemsDataSource .. similar to the ShoppingListDataSource

An alternative method would be to create a generic data source and data manager classes which would work for all classes.

The generic TableViewDataSource would be independent of the type of the class entity, cell or the data manager/data provider associated with an object. The declaration of the UITableViewDataSource is shown below:

class TableViewDataSource<CellType :UITableViewCell, Entity :ManagedObjectType>: NSObject, UITableViewDataSource, FetchedResultsDataProviderDelegate {

As you can see the TableViewDataSource is a generic class, where you can pass the type of the cell and the entity. Since, we are working with CoreData our entity classes inherit from a custom protocol ManagedObjectType which is our custom type. The TableViewDataSource initializer takes all the required parameters as shown below:

init(cellIdentifier :String,tableView :UITableView,dataProvider :FetchedResultsDataProvider<Entity>,cellConfigurationHandler :(CellType,Entity) -> ()) {self.cellIdentifier = cellIdentifierself.cellConfigurationHandler = cellConfigurationHandlerself.dataProvider = dataProviderself.tableView = tableViewsuper.init()}

One interesting thing to note is the dataProvider parameter which is also a generic type of FetchedResultsDataProvider. Let’s check out the code in the ShoppingListTableViewController which declares the data source and data providers.

private var dataSource :TableViewDataSource<ShoppingListTableViewCell,ShoppingList>!private var dataProvider :FetchedResultsDataProvider<ShoppingList>!

Next, we will initialize the dataSource and dataProvider properties with appropriate information.

override func viewDidLoad() {super.viewDidLoad()self.dataProvider = FetchedResultsDataProvider(managedObjectContext: self.managedObjectContext)self.dataSource = TableViewDataSource(cellIdentifier: “ShoppingListTableViewCell”, tableView: self.tableView, dataProvider: self.dataProvider, cellConfigurationHandler: { (cell :UITableViewCell, shoppingList :ShoppingList) incell.textLabel?.text = shoppingList.title})self.tableView.dataSource = self.dataSource}

Everything else remains the same! We have just replaced the concrete implementations of ShoppingList with a generic implementation. This means that we now do not have to create separate implementations for GroceryItemsDataSource and GroceryItemsDataManager.

At this point you must be thinking that a generic implementation is the best way to go and it will solve all your problems. Unfortunately, there is no silver bullet. You will definitely have much less code if you choose generic data source and data providers, but that comes with a cost. The cost is the amount of flexibility you will get when writing generic implementations. Generic means .. generic! This means that your implementation applies to several classes. If the participating classes diverge a little bit then your generic implementation needs to get updated to accommodate those changes.

We have reached the end of the series. I really enjoyed writing this series and hopefully it has helped you in writing cleaner and better code. I will end this post with a question for my readers which is stated below.

Which route will you choose when writing your separate data sources and data providers and why?

[Download Project]

iOS Developer, speaker and educator. Top Udemy and LinkedIn instructor. Lead instructor at DigitalCrafts. https://www.udemy.com/user/mohammad-azam-2/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store