Skip to content

Latest commit

 

History

History
249 lines (177 loc) · 10.8 KB

8.0 Migration Guide.md

File metadata and controls

249 lines (177 loc) · 10.8 KB

DTCollectionViewManager 8.0 Migration Guide

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.

Benefits of Upgrading

  • Unified and improved cell/view registration methods
  • New compact type-safe way of registering event closures.
  • Support for using unsubclassed UICollectionViewCell/UICollectionViewListCell/ UICollectionReusableView without ModelTransfer conformance.
  • Support for iOS 14 SDK delegate methods and TVCollectionViewDelegateFullScreenLayout protocol

Requirements

  • iOS 11.0 and higher / tvOS 11.0 and higher
  • Xcode 12 and higher
  • Swift 5.3 and higher
  • DTModelStorage 9.0 and higher

New features

Event closure registration

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.

Unsubclassed UICollectionViewCell\ UICollectionReusableView usage

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.

Improved registration methods

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 and handler closures are optional.

DTModelStorage additions

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
  }
}

iOS 14 SDK and TVCollectionViewDelegateFullScreenLayout

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

In-depth documentation

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.

Breaking changes

Xcode 12 / Swift 5.3

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.

Storyboard prototype cells and supplementary views

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
}

Registration methods

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.

Deprecations

Cell and supplementary view configurations

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 before ModelTransfer.update(with:) method

Registration methods

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"
}

Other deprecations

  • 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.