DTCollectionViewManager 8.0 is the latest major release of UICollectionView library for iOS and tvOS written in Swift. Following Semantic Versioning conventions, 8.0 introduces API-breaking changes.
- Unified and improved cell/view registration methods
- New compact type-safe way of registering event closures.
- Support for using unsubclassed
UICollectionViewCell
/UICollectionViewListCell
/UICollectionReusableView
withoutModelTransfer
conformance. - Support for iOS 14 SDK delegate methods and
TVCollectionViewDelegateFullScreenLayout
protocol
- iOS 11.0 and higher / tvOS 11.0 and higher
- Xcode 12 and higher
- Swift 5.3 and higher
- DTModelStorage 9.0 and higher
In previous releases you needed to specify cell type multiple times, when registering cell, and when registering each event. Now, you can register events for this mapping in mapping
closure:
// Previous releases
manager.register(PostCell.self)
manager.didSelect(PostCell.self) { cell, model, indexPath in
// collectionView(_:didSelectItemAt:)
}
manager.willDisplay(PostCell.self) { cell, model, indexPath in
// collectionView(_:willDisplay:forItemAt:)
}
// New
manager.register(PostCell.self) { mapping in
mapping.didSelect { cell, model, indexPath in
// collectionView(_:didSelectItemAt:)
}
mapping.willDisplay { cell, model, indexPath in
// collectionView(_:willDisplay:forItemAt:)
}
}
Those events are now tied to ViewModelMapping
instance, which means, that events, registered this way, will only trigger, if mapping condition of current mapping applies. For example:
manager.register(PostCell.self) { mapping in
mapping.condition = .section(0)
mapping.didSelect { cell, model, indexPath in
// This closure will only get called, when user selects cell in the first section
}
}
manager.register(PostCell.self) { mapping in
mapping.condition = .section(1)
mapping.didSelect { cell, model, indexPath in
// This closure will only get called, when user selects cell in the second section
}
}
New event closure registration now plays much more nicely with Xcode autocomplete, because of focused method visibility. For example, when you register events for UICollectionViewCell
, you will not see UICollectionReusableView
events in autocomplete, as well as events, not tied to cell / view.
Since library creation, ModelTransfer
was a protocol, upon which all mapping/registration/event closures relied on. It was not possible to use library without conforming your cell subclasses to this protocol.
DTCollectionViewManager
removes this restriction:
manager.register(UICollectionViewListCell.self, for: String.self) { mapping in
} handler: { cell, model, indexPath in
var content = cell.defaultContentConfiguration()
content.text = model
cell.contentConfiguration = content
}
Supplementary views also support the same syntax:
manager.registerHeader(UICollectionReusableView.self, for: String.self) { mapping in
} handler: { header, model, indexPath in
}
You can actually mix and match cells with ModelTransfer
protocol conformance and without, in the same UICollectionView
.
Please note, that for non-ModelTransfer views, only new style event registration - through
mapping
closure is available.
Example project contains view controller, that was setup using new cell and event registration styles.
In previous DTCollectionViewManager
releases, there were a lot of cell/view registration methods, some for registering nibless views, some with custom nibs etc. In order to simplify and unify registration methods, as well as introduce new ones, most of registration variants have been deprecated, and xib / xibless registration methods are being merged into one method.
For example, new cell registration method looks like this:
manager.register(PostCell.self) { mapping in
// customize mapping
} handler: { cell, model, indexPath in
// configure cell with model.
}
This registration works for xib-less cell registration as well as registering PostCell
xib. handler
closure replaces previously available configureCell
closure, which is now deprecated.
New syntax is backwards-compatible with old syntax without closures:
manager.register(PostCell.self)
-mapping
andhandler
closures are optional.
ViewModelMapping
class has been reworked from the ground up to allow holding generic information about reusable views and cells, as well as dequeuing configured views.
MemoryStorage
now has insertItems(_:at:)
method, that allows inserting collection starting from provided indexPath. This is useful for example if you show a list of items and a load more button/spinner, and want to insert new page of items between old items and paging cell:
try? manager.memoryStorage.insertItems(newPosts, at: IndexPath(item: self.numberOfItems - 1, section: 0))
ViewModelMapping
now has a new convenience method modelCondition
for conditional mappings:
manager.register(OddCell.self) { mapping in
mapping.condition = mapping.modelCondition { indexPath, model in
return indexPath.item.isOdd
}
}
Starting with iOS 14 / tvOS 14 / macCatalyst 14.0, cell registrations use UICollectionView.CellRegistration
and supplementary views registrations use UICollectionView.SupplementaryRegistration
. This has the benefit of autogenerating cell and supplementary reuse identifiers for you, so you don't have to manage them yourself.
iOS 14 SDK collectionView(_:canEditItemAt)
delegate method is now supported, event closure can be registered using canEdit
method.
tvOS 13 TVCollectionViewDelegateFullScreenLayout
delegate protocol is now fully supported too, providing event closures for all it's delegate methods.
Several event API's have been improved to allow returning nil for methods, that accept nil as a valid value:
contextMenuConfiguration
, previewForHighlightingContextMenu
, previewForDismissingContextMenu
Along with API reference, there is now extensive documentation, broken into sections for your convenience. It covers board range of topics, including datasources, events, mapping/registration and more.
This release requires Swift 5.3. Minimum iOS / tvOS deployment targets are unchanged (iOS 11, tvOS 11).
This release heavily relies on where clauses on contextually generic declarations, that are only available in Swift 5.3 - SE-0267.
Because cell/supplementary views registration methods have been merged, in order to register cells designed in storyboard, you need to specify this directly in mapping
closures:
register(StoryboardCell.self) { mapping in
mapping.cellRegisteredByStoryboard = true
}
registerHeader(StoryboardHeader.self) { mapping in
mapping.supplementaryRegisteredByStoryboard = true
}
Some registration methods now have a slightly different signature, and old methods have been made unavailable:
// previous releases
`register(_:mappingBlock:)`
// New syntax:
`register(_:mapping:)`
Upgrade shims provided for you to use Xcode fix-its in place to fix those methods.
configureCell
, configureHeader
, configureFooter
, configureSupplementary
methods have been deprecated and are being replaced with handler
parameter on registration methods.
// previous releases
manager.register(PostCell.self)
manager.configureCell(PostCell.self) { cell, model, indexPath in
cell.selectionStyle = .none
}
// 8.x release
manager.register(PostCell.self) { cell, model, indexPath in
cell.selectionStyle = .none
}
Please note, that due to how UICollectionView.CellRegistration works,
handler
closure is called beforeModelTransfer.update(with:)
method
Several cell/header/footer/supplementary view registration methods have been deprecated to unify registration logic. Please use register(_:mapping:handler:)
, registerHeader(_:mapping:handler:)
, registerFooter(_:mapping:handler:)
and registerSupplementary(_:forKind:mapping:handler:)
as a replacements for all of those methods.
Some examples of replacement API's for deprecated methods:
// Old
manager.registerNibless(PostCell.self)
// New
manager.register(PostCell.self)
// Old
manager.registerNibNamed("FooCell", for: PostCell.self)
// New
manager.register(PostCell.self) { mapping in
mapping.xibName = "FooCell"
}
DTCollectionViewManager.configureEvents(for:_:)
is deprecated, it's functionality has become unnecessary since mapping closure of cell/supplementary registration now captures both cell and model type information for such events.DTCollectionViewManager.configureDiffableDataSource(modelProvider:)
is deprecated for non-hashable data models. Please use configureDiffableDataSource method for models, that are Hashable. From Apple's documentation:If you’re working in a Swift codebase, always use UICollectionViewDiffableDataSource instead
.