Part 4 in a series on “fixing” Model-View-Controller:
There are other ways you can apply these principles to writing more maintainable apps.
View Controller-based Cells
One that I’m really interested in and am actively researching is how to use view controllers as cell content.
Cells can be really complicated things, architecturally. If you have any sort of dynamic content in a cell, you’re often faced with weird situations where you wonder “where does this logic belong?”. Do you put image loading in your view subclass? Allow your cell to handle complex business logic? Tack on additions to the list’s delegate protocol so you can message things back out (which then just complicates your list view controller)?
Using view controllers as cells helps answer these questions. It is natural to place this sort of code in the view’s controller, and the fact that the view happens to be a cell doesn’t really make a difference to the underlying principle.
Small finite lists
It’s really easy to make a view controller a cell when you have a list of a finite size. You have your “ListViewController”, and you give it an array of view controllers. It adds them as children, and then pulls out the appropriate one when its time to show a cell, and sticks the view controller’s
view inside the cell’s
You can then apply the same principles of “flow view controllers” and “mini view controllers” to the content of the cell, and use child view controllers to manage portions or variations of the cell. I used to write a Mac app where I used this approach, and I could sometimes get upwards of 15 view controllers in a single cell. Granted, the cells were pretty complicated in what they could do, but none of these view controllers was longer than 100 lines of code. It made debugging issues trivially easy.
At this level of granularity in a finite list, you also probably aren’t very worried about view lifecycle callbacks, because you can pre-allocate everything.
Huge finite lists
Once you start moving past the point where you can pre-allocate everything, you have two main approaches you can take. The first approach (“huge finite lists”) is like what the current
UICollectionView API offer: you know up-front how many items are in a section. In this case, your
ListViewController would likely have a similar looking datasource API as
UITableView, where it progressively asks for view controllers and then uses the underlying “willBeginDisplayingCell:” etc callbacks to notify on lifecycle.
At this level you might also want to start thinking about view controller reuse, but I would probably avoid thinking about that unless I measured and determined that view controller deallocation and initialization was a measurable bottleneck.
Then there’s the problem of infinity. A great example of this is the main screen of the Reddit app. You can scroll forever, and the content will just keep loading and loading… there’s no way to know up-front how much content there is. With this, you’ll be looking at loading in “slices” of the infinite view controller sequence, or taking a page (haha) out of
UIPageViewController‘s book and using the “doubly-linked list” sort of API (“what’s the view controller after
A? What’s the view controller after
You’ll still have the underlying callbacks to help manage view lifecycle, and you’ll also still have to consider view controller reuse as an option.
As you get in to this style of programming, you’ll find that you end up developing a decent amount of boilerplate around embedding view controllers. That is to be expected, because the view controller containment APIs tend to offer the bare minimum to do what you need.
As you find situations where the API can be improved, please request that these improvements be made in the system frameworks.
There’s a lot to digest in these posts. Some people may scream in horror at the idea of “view controllers as cells”, but it’s an idea worth exploring.
So, the huge TL;DR of this is:
- Decompose your UI using view controllers
- Use view controllers to manage sequence
- View controllers don’t have to fill the screen