我正在尝试追踪应用程序中的严重崩溃。
我有一些代码可以有效地做到这一点:
if let indexPath = self.tableView.indexPath(for: myTableViewCell) {
// .. update some state to show a different view in the cell ..
self.tableView.reloadData()
// show nice fade out of the cell
self.friendRequests.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .fade)
}
担心的是调用 reloadData() 以某种方式使我刚刚检索到的 indexPath 无效,因此应用程序在尝试删除该 indexPath 处的单元格时崩溃。这可能吗?
编辑:
用户交互是这样的:
- 用户点击 TableView 单元格内的按钮 [添加 friend ] <-- indexPath 在此处检索
- 将按钮更改为 [已添加] 以显示已收到点击。 <-- 此处调用 reloadData
- 在短暂延迟(0.5 秒)后淡出单元格。 <-- 从#1 中使用 indexPath 调用此处删除
我可以更改我的代码以不调用 reloadData 而只是更新单元格的 View 。这是可取的吗?如果我不这样做会发生什么?
最佳答案
就我个人而言,我只是重新加载有问题的按钮 reloadRows(at:with:)
,而不是整个 TableView 。这不仅效率更高,而且如果您还没有滚动到列表顶部,它还可以避免滚动列表时出现不和谐的情况。
然后我会推迟 deleteRows(at:with:)
动画的一小部分时间。我个人认为 0.5 秒太长了,因为用户可能会继续点击另一行,如果他们不幸在动画期间的错误时间点击,他们很容易得到与预期不同的行。您希望延迟足够长,以便他们对他们点击的内容得到肯定的确认,但又不会长到产生令人困惑的用户体验。
无论如何,你最终会得到这样的结果:
func didTapAddButton(in cell: FriendCell) {
guard let indexPath = tableView.indexPath(for: cell), friendsToAdd[indexPath.row].state == .notAdded else {
return
}
// change the button
friendsToAdd[indexPath.row].state = .added
tableView.reloadRows(at: [indexPath], with: .none)
// save reference to friend that you added
let addedFriend = friendsToAdd[indexPath.row]
// later, animate the removal of that row
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
if let row = self.friendsToAdd.index(where: { $0 === addedFriend }) {
self.friendsToAdd.remove(at: row)
self.tableView.deleteRows(at: [IndexPath(row: row, section: 0)], with: .fade)
}
}
}
(注意,我使用 ===
是因为我使用的是引用类型。我会使用 ==
和符合 Equatable 的值类型
如果处理值类型。但这些是与您的更大问题无关的实现细节。)
产生:
关于ios - 在获取 indexPath 之后但在删除该 indexPath 处的单元格之前调用 reloadData() 是否不安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42984732/