[UITableViewDiffableDataSource] How to embed UITextView in UITableViewCell with UITableView.automaticDimension for cell height.

The problem:
1. You have UITableView with UITableView.automaticDimension for cell height.

2. You have a simple cell, that embed UITextView into .contentView.

3. UITextView, of course, disables its scroll.

Question:
How to expand/change cell size by using only UITableViewDiffableDataSource?

Actual:
In documentation object (MyViewModel) that represents view model for a corresponding cell, should conform to Hashable protocol. It is done for "diffing" on "Array" concept level ( operations as Insert and Delete ).
How to react on update operations in this case?
NOT a solution:
I found in a blog postthat I have to call tableView.begin/end updates on text did changed.
It is a hack.
However, it works as expected and I would like to hear different solutions and appropriate patterns about Diffable datasource.
Thanks!

Replies

Hi!
I have the same layout ( I guess ) where I put a textView ( actually, a subview of subview (of subview...) of cell content view is text view ).
Sorry, and yes, it is only one solution so far.
You can, for example, check this solution on iOS 14, maybe it is not required anymore and it works as expected ( automagically ).

What about your question?
Well, it is long story and it should be covered or solved easily in iOS 14 by Cell Configurations.

Consider you have a ViewModel:

Code Block
class ViewModel {
var first: Id
var second: String
}


It is a simple model and it can be easily conformed to Hashable.

But, however, we don't know how it will going in future, right?
I suggest to add another creature:

Code Block
extension ListViewModel {
struct Row {
var viewModel: ViewModel
var diffable: Diffable
struct Diffable {
var id: Id
var first: String
var second: Int
}
}
}


You add additional Row model which represents a model for your Cell and, especially, for a List of Cells.
It is not the same as ListViewModel.Entry. It is an ItemIdentifierType for DiffableDataSource.

I intentionally put it in ListViewModel namespace, because it works with ViewModel and embraces it into self and conforms to necessary protocols.

Code Block
extension ListViewModel.Row: Hashable {
static func == (lhs: Self, rhs: Self) {
lhs.diffable == rhs.diffable
}
func hash(_ inout hasher: Hasher) {
hasher.hash(self.diffable)
}
}


As you see, I separate an intention of Row and its nature.
It is intended to be an ItemIdentifierType for DiffableDataSource, BUT, it is not what it actually is.
Actually, it is projection of viewModel on properties of cell AND states of cell.

So, here we distinguish a projection and ItemIdentifier. I called it Diffable, because we would check if our view states that are computed from model did change.

Why this solution would work?
First of all, it doesn't rely on view model itself, only on properties for cell and states for cell.
Second, it requires that some structure ( Diffable in our case ) contains all these states and properties inside to compute difference.

Does it look similar to Cell Configuration from iOS 14?