【问题标题】:Why return nil tableViewCell for UITableViewDiffableDataSource cellProvider param?为什么为 UITableViewDiffableDataSource cellProvider 参数返回 nil tableViewCell?
【发布时间】:2019-06-11 11:45:42
【问题描述】:

iOS 13 有一些新的 API 用于处理 tableViewAPI 的一个有趣领域是cell 提供者 参数UITableViewDiffableDataSource

public typealias CellProvider = (UITableView, IndexPath, ItemIdentifierType) -> UITableViewCell?

什么时候适合在这里返回nilUITableViewCell

【问题讨论】:

    标签: swift ios13


    【解决方案1】:

    所以这个 API 仍处于测试阶段,这意味着 documentation 不完整。

    它说:

    本文档包含有关正在开发的 API 或技术的初步信息。此信息可能会发生变化,根据本文档实施的软件应使用最终的操作系统软件进行测试。

    TLDR - 从现在开始,如果您创建 UITableView 并使用返回 nil 的 UITableViewDiffableDataSource,您的应用将会崩溃。

    不过,this 博客文章会介绍一些新的细节。它没有提到任何关于为单元格返回 nil 的内容。

    您还可以查看this WWDC 会议。在 15 分钟左右,您可以看到如果无法创建单元格,示例代码将引发致命错误。

    使用上面的博客,我像这样在 Xcode 11 中制作了一个简单的 tableView

    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 上查看full project

    【讨论】:

    • 抱歉,为了清楚起见。看看我的问题,即“为什么返回 nil”。你的回答是“我不知道”。 ?
    • 我更新了我的答案以更清楚。并不是真的“我不知道”,更多的是没有文档,并且根据我提供的示例代码返回 nil 会导致应用程序崩溃。你想知道为什么返回 nil 吗?你想要崩溃。
    猜你喜欢
    • 1970-01-01
    • 2014-11-11
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    相关资源
    最近更新 更多