swift - 插入和删除时出现 'NSInternalInconsistencyException',第 0 节中的无效行数错误?

标签 swift xcode uitableview

尝试插入一行时,tableview 崩溃并显示“'无效​​更新:第 0 节中的行数无效。更新 (1) 后现有节中包含的行数必须等于行数更新前包含在该部分中的 (0),加上或减去从该部分插入或删除的行数(0 插入,0 删除),加上或减去移入或移出该部分的行数(0 移入, 0 移出)。'" 当我尝试删除一行说“'尝试将第 0 行插入第 0 节,但更新后第 0 节中只有 0 行'”

这是一个从 Github 克隆的 SDK,名为 antidote.tried 仅使用 tableview.reloaddata() 而不是开始和结束更新,反之亦然。

相同的链接是:https://github.com/Antidote-for-Tox/Antidote

friend 列表 Controller

super.viewDidLoad()

    let friends = submanagerObjects.friends()
    let requests = submanagerObjects.friendRequests()
    dataSource = FriendListDataSource(theme: theme, friends: 
friends, requests: requests)
    dataSource.delegate = self

    tableView.tableFooterView = UIView()

    updateViewsVisibility()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    updateViewsVisibility()
}

extension FriendListController: FriendListDataSourceDelegate {

    func friendListDataSourceBeginUpdates() {
        tableView.beginUpdates()
    }

    func friendListDataSourceEndUpdates() {
        tableView.endUpdates()
        updateViewsVisibility()
    }

    func friendListDataSourceInsertRowsAtIndexPaths(_ indexPaths: [IndexPath]) {
        tableView.insertRows(at: indexPaths, with: .automatic)
    }

    func friendListDataSourceDeleteRowsAtIndexPaths(_ indexPaths: [IndexPath]) {
        tableView.deleteRows(at: indexPaths, with: .automatic)
    }

    func friendListDataSourceReloadRowsAtIndexPaths(_ indexPaths: [IndexPath]) {
        tableView.reloadRows(at: indexPaths, with: .automatic)
    }

    func friendListDataSourceInsertSections(_ sections: IndexSet) {
        tableView.insertSections(sections, with: .automatic)
    }

    func friendListDataSourceDeleteSections(_ sections: IndexSet) {
        tableView.deleteSections(sections, with: .automatic)
    }

    func friendListDataSourceReloadSections(_ sections: IndexSet) {
        tableView.reloadSections(sections, with: .automatic)
    }

    func friendListDataSourceReloadTable() {
        tableView.reloadData()
    }
}

extension FriendListController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: FriendListCell.staticReuseIdentifier) as! FriendListCell
        let model = dataSource.modelAtIndexPath(indexPath)

        cell.setupWithTheme(theme, model: model)

        return cell
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return dataSource.numberOfSections()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.numberOfRowsInSection(section)
    }

    func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return dataSource.sectionIndexTitles()
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return dataSource.titleForHeaderInSection(section)
    }

    func tableView(_ tableView: UITableView, commit editingStyle: 
UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            let title: String

            switch dataSource.objectAtIndexPath(indexPath) {
            case .request:
                title = String(localized:"delete_contact_request_title")
            case .friend:
                title = String(localized:"delete_contact_title")
            }

            let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)

            alert.addAction(UIAlertAction(title: String(localized: "alert_cancel"), style: .default, handler: nil))
            alert.addAction(UIAlertAction(title: String(localized: "alert_delete"), style: .destructive) { [unowned self] _ -> Void in

                switch self.dataSource.objectAtIndexPath(indexPath) {
                case .request(let request):
                    self.submanagerFriends.remove(request)
                case .friend(let friend):
                    do {
                        let chat = 
 self.submanagerChats.getOrCreateChat(with: friend)

                        try self.submanagerFriends.remove(friend)
                        self.submanagerChats.removeAllMessages(in: chat, removeChat: true)
                    } catch let error as NSError {
                             handleErrorWithType(.removeFriend, error: error)
                        }
                 }
            })

            present(alert, animated: true, completion: nil)
        }
    }
}

friend 列表数据源

private extension FriendListDataSource {

    func addNotificationBlocks() {
        requestsToken = requests?.addNotificationBlock { [unowned self] change in
        switch change {
        case .initial:
            break
        case .update(let requests, let deletions, let insertions, let modifications):
            guard let requests = requests else { return }
            if deletions.count > 0 {
                self.delegate?.friendListDataSourceReloadTable()
                return
            }
            self.delegate?.friendListDataSourceBeginUpdates()

            let countAfter = requests.count
            let countBefore = countAfter - insertions.count + deletions.count

            if countBefore == 0 && countAfter > 0 {
                self.delegate?.friendListDataSourceInsertSections(IndexSet(integer: 0))
            } else { 
                    self.delegate?.friendListDataSourceDeleteRowsAtIndexPaths(deletions.map { IndexPath(row: $0, section: 0)} )
                    self.delegate?.friendListDataSourceInsertRowsAtIndexPaths(insertions.map { IndexPath(row: $0, section: 0)} )
                    self.delegate?.friendListDataSourceReloadRowsAtIndexPaths(modifications.map { IndexPath(row: $0, section: 0)} )  
                }
                 self.delegate?.friendListDataSourceEndUpdates()
        case .error(let error):
            fatalError("\(error)")
        }
    }

它应该在没有崩溃的情况下工作,但它在插入和删除时崩溃,前者产生“'无效更新:第 0 节中的行数无效。更新 (1) 后现有部分中包含的行数必须是等于更新前该部分中包含的行数 (0),加上或减去从该部分插入或删除的行数(0 插入,0 删除)加上或减去移入或移出的行数那个部分(0 个搬进来,0 个搬出去)。'" 后者产生:“'尝试将第 0 行插入第 0 节,但更新后第 0 节中只有 0 行。'”

感谢任何帮助。

最佳答案

根据 UITableView类,您必须使用以下之一:

  • performBatchUpdates(_:completion:) ( link )
  • func beginUpdates() ( link ) 然后是 func endUpdates() ( link )

您必须在批量更新 block 内执行所有更新(或在开始和结束更新函数之间)(包括数据源更新 - 不仅是插入/删除/移动/重新加载)

这样你就可以避免崩溃。

例如:

var dataSource: [Int] = [1, 2, 3]

tableView.beginUpdates()
dataSource.append(4)
tableView.insertRows(at: [IndexPath(row: 3, section: 0)], with: .automatic)
tableView.endUpdates()

关于swift - 插入和删除时出现 'NSInternalInconsistencyException',第 0 节中的无效行数错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57158143/

相关文章:

iOS UIBarButtons 不设置由 UIActionSheet iOS 6.1 启用

UITableView 从顶部到 topLayoutGuide 以编程方式插入内容

ios - Swift 中 UIScrollView 内的 UITableView 高度

ios - UINavigationController 和 UITabBarController 的关系是否与 UIViewController 相同?

xcode - 如何在调试时仅打印 Swift 结构的自定义描述,而不打印其他内容?

swift - 如何在 Swift 中读取 3 个字节中的 19 位?

swift - NSCopying 副本(带有 :) - Does it really need to return Any?

ios - 如何使用 Xcode 5 可视化调试器快速查看自定义对象?

ios - 如何重新加载 tableview 的特定部分

ios - 无法从 Parse iOS Swift 查询用户名