Зачем возвращать ноль tableViewCell для параметра cellProvider UITableViewDiffableDataSource?
iOS 13 имеет новый API для обработки tableView
и одна интересная область API является cell
параметр провайдера UITableViewDiffableDataSource
public typealias CellProvider = (UITableView, IndexPath, ItemIdentifierType) -> UITableViewCell?
Когда было бы целесообразно вернуть nil
UITableViewCell
Вот?
1 ответ
Таким образом, этот API все еще находится в стадии бета-тестирования, что означает, что документация не завершена.
Здесь утверждается:
Эта документация содержит предварительную информацию о разрабатываемом API или технологии. Эта информация может быть изменена, и программное обеспечение, реализованное в соответствии с этой документацией, должно быть протестировано с окончательной версией программного обеспечения операционной системы.
TL; DR - на данный момент, если вы создаете UITableView
и использовать UITableViewDiffableDataSource
который возвращает nil, ваше приложение выйдет из строя.
Однако в этом сообщении блога рассматриваются некоторые новые детали. Однако в нем ничего не говорится о возврате nil для ячейки.
Вы также можете взглянуть на этот сеанс WWDC. Примерно через 15 минут вы можете увидеть, что пример кода выдает фатальную ошибку, если ячейка не может быть создана.
Используя приведенный выше блог, я сделал простой tableView в Xcode 11, подобный этому
class ViewController: UIViewController {
enum Section: CaseIterable {
case friends
case family
case coworkers
}
struct Contact: Hashable {
var name: String
var email: String
}
struct ContactList {
var friends: [Contact]
var family: [Contact]
var coworkers: [Contact]
}
private let tableView = UITableView()
private let cellReuseIdentifier = "cell"
private lazy var dataSource = makeDataSource()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self,
forCellReuseIdentifier: cellReuseIdentifier
)
tableView.dataSource = dataSource
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
loadData()
}
func makeDataSource() -> UITableViewDiffableDataSource<Section, Contact> {
let reuseIdentifier = cellReuseIdentifier
return UITableViewDiffableDataSource(
tableView: tableView,
cellProvider: { tableView, indexPath, contact in
let cell = tableView.dequeueReusableCell(
withIdentifier: reuseIdentifier,
for: indexPath
)
cell.textLabel?.text = contact.name
cell.detailTextLabel?.text = contact.email
return cell
}
)
}
func update(with list: ContactList, animate: Bool = true) {
let snapshot = NSDiffableDataSourceSnapshot<Section, Contact>()
snapshot.appendSections(Section.allCases)
snapshot.appendItems(list.friends, toSection: .friends)
snapshot.appendItems(list.family, toSection: .family)
snapshot.appendItems(list.coworkers, toSection: .coworkers)
dataSource.apply(snapshot, animatingDifferences: animate)
}
func loadData() {
let friends = [
Contact(name: "Bob", email: "Bob@gmail.com"),
Contact(name: "Tom", email: "Tom@myspace.com")
]
let family = [
Contact(name: "Mom", email: "mom@aol.com"),
Contact(name: "Dad", email: "dad@aol.com")
]
let coworkers = [
Contact(name: "Mason", email: "tim@something.com"),
Contact(name: "Tim", email: "mason@something.com")
]
let contactList = ContactList(friends: friends, family: family, coworkers: coworkers)
update(with: contactList, animate: true)
}
}
Все загружается нормально, поэтому я решил посмотреть, что произойдет, если я верну nil для ячейки, поэтому я добавил этот код в UITableViewDiffableDataSource
:
if contact.name == "Bob" {
return nil
}
Это привело к сбою:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource returned a nil cell for row at index path: <NSIndexPath: 0xd6d99b18b93a5a0e> {length = 2, path = 0 - 0}. Table view: <UITableView: 0x7f8d30006200; frame = (-207 -448; 414 896); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x60000239de00>; layer = <CALayer: 0x600002dd0ec0>; contentOffset: {0, 0}; contentSize: {414, 264}; adjustedContentInset: {0, 0, 0, 0}; dataSource: <_TtGC5UIKit29UITableViewDiffableDataSourceOC5iOS1314ViewController7SectionVS2_7Contact_: 0x600002ffc520>>, dataSource: <_TtGC5UIKit29UITableViewDiffableDataSourceOC5iOS1314ViewController7SectionVS2_7Contact_: 0x600002ffc520>'
Фактически, просто возврат nil (без ячейки) также вызывает сбой, как только источник данных применяет обновление. Итак, на данный момент, насколько я могу судить, возвращение nil не является реальным вариантом, поскольку вызывает сбой.
Вы можете проверить полный проект на github.