Skip to content

Latest commit

 

History

History
207 lines (148 loc) · 8.6 KB

8.0 Migration Guide.md

File metadata and controls

207 lines (148 loc) · 8.6 KB

DTTableViewManager 8.0 Migration Guide

DTTableViewManager 8.0 is the latest major release of UITableView 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 UITableViewCell/UITableViewHeaderFooterView without ModelTransfer conformance.

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
    // tableView(_:didSelectRowAt:)
}
manager.willDisplay(PostCell.self) { cell, model, indexPath in
  // tableView(_:willDisplay:forRowAt:)
}

// New
manager.register(PostCell.self) { mapping in
    mapping.didSelect { cell, model, indexPath in
      // tableView(_:didSelectRowAt:)
    }
    mapping.willDisplay { cell, model, indexPath in
      // tableView(_:willDisplay:forRowAt:)
    }
}

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 UITableViewCell, you will not see UITableViewHeaderFooterView events in autocomplete, as well as events, not tied to cell / view.

Please note, that new event style registration is only available for UITableViewHeaderFooterView and subclasses.

Unsubclassed UITableViewCell\ UITableViewHeaderFooterView 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.

DTTableViewManager removes this restriction:

manager.register(UITableViewCell.self, for: String.self) { mapping in

} handler: { cell, model, indexPath in
  cell.textLabel.text = model
}

Header/footer views also support the same syntax:

manager.registerHeader(UITableViewHeaderFooterView.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 UITableView.

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

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.

Deprecations

Cell and supplementary view configurations

configureCell, configureHeader, configureFooter 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 handler closure is called before ModelTransfer.update(with:) method

Registration methods

Several cell/header/footer view registration methods have been deprecated to unify registration logic. Please use register(_:mapping:handler:), registerHeader(_:mapping:handler:) and registerFooter(_: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

  • DTTableViewManager.configureEvents(for:_:) is deprecated, it's functionality has become unnecessary since mapping closure of cell/header/footer registration now captures both cell and model type information for such events.
  • DTTableViewManager.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 UITableViewDiffableDataSource instead.
  • TableViewUpdater.usesLegacyTableViewUpdateMethods property.