Conditional mappings is a feature, that allows you to specify, where this mapping will be active. It's useful in cases, where you want the same data model to be displayed in different cells or using different layouts.
Section condition allows you to limit mapping to a single section:
manager.register(PostCell.self) { mapping in
// This mapping will only be used in PostCell.ModelType is displayed in first section
mapping.condition = .section(0)
}
Model condition gives you fine-grained control over which mapping is used:
manager.register(OddCell.self) { mapping in
mapping.condition = mapping.modelCondition { model, indexPath in
return indexPath.item.isOdd
}
}
Keep in mind, that while DTCollectionViewManager
implements conditional mappings, UICollectionView
does not have a clue, that this is happening. This may cause issues in several cases, shown below:
manager.register(PostCell.self) { mapping in
mapping.condition = .section(0)
}
mapping.register(PostCell.self) { mapping in
mapping.condition = .section(1)
mapping.xibName = "CustomPostCell"
}
In this example we are trying to show two different designs of cells in first and second section. The issue is, even if we have different xib names, reuse identifier for both of those registrations is the same - "PostCell". So when the cell is dequeued, the last registration would be used by UICollectionView
, breaking the first mapping. Appropriate fix for this situation would be setting custom reuseIdentifier:
manager.register(PostCell.self) { mapping in
mapping.condition = .section(0)
}
mapping.register(PostCell.self) { mapping in
mapping.condition = .section(1)
mapping.xibName = "CustomPostCell"
mapping.reuseIdentifier = "custom-post-cell"
}
This way cells would get registered under different reuse identifiers, and dequeue will work correctly.
On iOS 14 / tvOS 14 and higher, this issue will not be happening, because UICollectionView.CellRegistration API uses auto-generated reuse identifiers.
manager.register(PostCell.self)
manager.register(VideoPostCell.self) { mapping in
mapping.condition = mapping.modelCondition { indexPath, model in
return model.containsVideo
}
}
In this case, we have two mappings for the same data model - Post
. Second mapping needs to work when post contains video, and first mapping - in other cases. The issue here is that first mapping does not have condition, and therefore when DTCollectionViewManager
starts searching for mapping for post with Video, it finds two mappings instead of one. The first mapping would be used, which, in this case, is incorrect.
The fix to this would be to use mapping conditions, that don't intersect between each other:
manager.register(PostCell.self) { mapping in
mapping.condition = mapping.modelCondition { indexPath, model in
return !model.containsVideo
}
}
manager.register(VideoPostCell.self) { mapping in
mapping.condition = mapping.modelCondition { indexPath, model in
return model.containsVideo
}
}