Over the years, I’ve come to learn that I rarely want to directly add content to my UITableViewCell
and UICollectionViewCell
s. I’ve landed on creating UIView
s instead, which are contained fully within a cell – for the sake of versatility, reusability, and simplicity. iOS 14 introduces a new type: UIContentConfiguration
. I’ll also touch on it and why I prefer not to use it.
Benefits of Building UIView
s over UITableViewCell
s
Reusability
One of the main benefits of building UIView
s as subviews is reusability. When you build your custom UI elements as subviews, you can reuse them in other parts of your app. Views can be reused within UITableViewCell
, UICollectionViewCell
, or as part of a larger UIView
. By building it as a subview, you can easily add it to any other view or cell without duplicating code.
Better Separation of Concerns
Another benefit of building UIView
s as subviews is better separation of concerns. When you build your custom UI elements as subviews, you can separate the view logic from the cell logic. This can make your code more modular and easier to understand. It also makes it easier to test and debug your code.
For example let’s create a cell that contains a single ContactView
as its child view:
import UIKit
final class ContactCell: UITableViewCell {
private let view = ContactView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
view.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(view)
NSLayoutConstraint.activate([
view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
view.topAnchor.constraint(equalTo: contentView.topAnchor),
view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
])
}
func bind(viewModel: ContactView.ViewModel) {
view.bind(viewModel: viewModel)
}
// MARK: - Unavailable
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In this view, we only worry about things at the cell level. We could modify the separatorInset
, or tackle behaviors and properties specific to the cell — or further insetting our view to match design constraints. For example, we may for one reason or another want to create a fake insetGrouped
style which is managed by the cell. By having the view and its logic handled elsewhere, we can simplify the process of customization.
Composition
When built this way, more complex views can be composed together. Moreover, the ViewModel
s can be composed together, providing a much more robust and reusable solution. Since each view can be tested in isolation or when integrated, more of the application can be tested at a time.
The New iOS 14 Content Configuration API
In iOS 14, Apple introduced the Content Configuration API, which provides a new way to customize the appearance and behavior of table and collection view cells. The Content Configuration API is designed to work with custom UIViews
that are embedded in the cell’s contentView
. When you use the Content Configuration API, you can specify the layout and behavior of your custom UI elements, while still leveraging the cell’s caching and reuse mechanisms.
However, I don’t prefer to use this API as we cannot be specific over which implementation of each protocol is accepted by a particular cell or view. As a result, it can lead to an over-abundance of type checking in production code.
Conclusion
In this blog post, we’ve explored why you should prefer to build UIView
s to be embedded in UITableViewCell
or UICollectionViewCell
instead of working directly with the cell. We’ve covered the benefits of reusability and better separation of concerns, as well as performance considerations. We’ve also discussed the new iOS 14 Content Configuration API and how it can be used with custom subviews to achieve better customization and performance.
By building your custom UI elements as subviews, you can create modular and reusable code, which can save you time and effort in the long run. You can also take advantage of the performance benefits of table and collection view cell caching.