Can row.value be replaced with a CBModel-based instance?

data_modelling

#1

If we were to improve the GrocerySync app, the document retrieved in - (void)couchTableSource:(CBLUITableSource*)source willUseCell:(UITableViewCell*)cell forRow:(CBLQueryRow*)row should be really a Task (subclass of CBLModel). So, instead of:

NSDictionary* rowValue = row.value;

we would retrieve it like so:

Task *task = row.value;

Is there a way to replace the default NSDictionary-based row values with their CBLModel counterpart? Otherwise, instantiating the model object every time we return the cell would be wasteful because we would be repeating the work if cells were being reused. Any ideas?


#2

Yeah, the idiom for this is [Task modelForDocument: row.document].

For examples of this you can look at ToDoLite, which uses CBLModel extensively.


#3

Thanks Jens. I see the following implementation in the ToDoLite app:

- (UITableViewCell *)couchTableSource:(CBLUITableSource *)source cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Task";
    TaskTableViewCell *cell = (TaskTableViewCell *)[source.tableView
                                                    dequeueReusableCellWithIdentifier:CellIdentifier
                                                    forIndexPath:indexPath];
    CBLQueryRow *row = [source rowAtIndex:indexPath.row];
    Task *task = [Task modelForDocument:row.document];
    cell.task = task;
    cell.delegate = self;

    return cell;
}

Unless I’m missing something, a Task object is being generated each time, even if the row/cell is being reused. If so, this seems suboptimal because the given row.document could certainly end up being instantiated more than once.

I was hoping to replace the source (containing dictionaries by default) with CBLModel-type objects before the UI starts to be displayed. Ideally then, we would have:

CBLQueryRow *row = [source rowAtIndex:indexPath.row];
Task *task = row.document;

… which would not require the source document to be instantiated into its CBLModel counterpart. Am I missing something?


#4

Yes, you’re missing something :wink:

First, Document objects are cached. There will only be one Document instance at a time for a given docID, within the scope of a Database instance. (It’s a weak cache, so if nothing else is referencing a Document, it will be dealloced. But the most recent 50 Documents will stick around even if unreferenced.)

Second, every Document has a (nullable, weak) reference to its Model, so there will only be one Model instance for a Document at a time. (Also, a Model with unsaved changes is held in memory until it’s saved, to avoid data loss.)

The result is that +modelForDocument: is pretty efficient.


#5

See? I knew I was missing something :smile:

Sounds the right thing to do and is, as you say, pretty efficient. Thanks for the explanation Jens.