【问题标题】:Intermittent Crash: Attempt to delete row 0 from section 0 which only contains 0 rows before the update间歇性崩溃:尝试从第 0 部分中删除第 0 行,该部分在更新前仅包含 0 行
【发布时间】:2019-02-28 06:20:48
【问题描述】:

我们已经为我们的应用实现了滑动删除功能,但不知何故,我们在 Crashlytics 上看到了这种间歇性的 prod 崩溃。

我一直在关注有关此崩溃的几篇 StackOverflow 帖子,但我无法获得此崩溃的确切原因。

我已尝试多次产生此崩溃,但每次都正常。

任何想法或想法,如果我在这里做错了什么?下面是崩溃报告和当前运行的代码 sn-p。

@available(iOS 11.0, *)
private func actionForType(alertID: String, swipeAction: AlertSwipeActionType, indexPath: IndexPath) -> UIContextualAction {
    let contexualAction = UIContextualAction(style: .normal, title: nil) { [weak self] (action, view, completion) in

        guard let strongSelf = self else {
            return
        }

        switch swipeAction {
        ......
        case .affirm:
            completion(true)
            strongSelf.dispositionAlert(id: alertID, status: true, indexPath: indexPath)
        ......
        }
    }

    ......
    return contexualAction
}

fileprivate func dispositionAlert(id: String, status: Bool, indexPath: IndexPath) {
    let dispositionRequest = AlertDispositionUpdateBody(id: id, disposition: status, questionId: nil)
    self.updateAlertDispositionStatus(request: dispositionRequest) { [weak self] in

        guard let strongSelf = self else {
            return
        }
        strongSelf.removeCellWithAnimationAt(indexPath: indexPath)
        strongSelf.loadAlerts()
    }
}

fileprivate func removeCellWithAnimationAt(indexPath: IndexPath) {
    DispatchQueue.main.async {
        self.tableView.beginUpdates() // likely not required
        self.removeAlertAtIndexPath(indexPath)
        self.tableView.deleteRows(at: [indexPath], with: .fade)
        self.tableView.endUpdates() // likely not required either
    }
}

@objc func loadAlerts() {
    self.startLoadingAnimation()
    self.alertsFooterList.removeAll()

    AlertsManager.sharedInstance.loadMemberAlerts()
}

fileprivate func removeAlertAtIndexPath(_ indexPath: IndexPath) {
    let alertStatus = self.alertTabType.statusToLoad[indexPath.section]
    if let alerts = self.alertsList[alertStatus], 
       alerts.count > indexPath.row {
       self.alertsList[alertStatus]?.remove(at: indexPath.row)
    }
}

【问题讨论】:

  • 您确定在调用removeCellWithAnimationAt 方法之前,您的表格单元格已加载吗?还是单元格已被删除,并且此方法被调用了两次?
  • 崩溃分析给出行号和功能你能分享这些细节吗?

标签: ios swift uitableview swift4.2


【解决方案1】:

崩溃告诉您发生了什么:当您尝试删除已被删除的行时。现在这看起来很奇怪,因为当您呈现 alertView 时该行就在那里。因此,在显示 alertView 和删除行之间,该行已被其他来源删除。阅读您的代码显然是可能的。在显示 alertview 和删除行之间有两个延迟。第一个是用户确认删除之前可能需要很长时间,第二个是DispatchQueue.main.async,它通常很快,但仍然会导致这些类型的错误。

不要记录要删除的 indexPath(因为 indexPath 可能会在用户确认时更改),而是记录您尝试删除的项目的 ID。当用户最终确认警报时,然后查找它在 tableview 中的位置,如果找到则将其删除。

更深层次的问题是您有两个事实来源 - 表格视图和您的数据源,它们不同步。最好先更新您的数据源,然后使用自动同步 tableview 的代码。这样,它们始终保持同步。 https://github.com/Instagram/IGListKit 是已经实现了这一点的解决方案,您可能会通过使用它来获得价值。

【讨论】:

  • 我不必使用该套件,但您的洞察力帮助我解决了问题。
【解决方案2】:

如果您使用 tableview 删除行调用,则首先调用部分的编号。 下面的代码。

代码: swift

fileprivate func removeCellWithAnimationAt(indexPath: IndexPath) {
    DispatchQueue.main.async {
        self.removeAlertAtIndexPath(indexPath)
        self.tableView.numberOfRows(inSection: indexPath.section) // called first
        self.tableView.deleteRows(at: [indexPath], with: .fade)
    }
}

我希望这段代码能正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多