将 UITableView 与自定义单元格一起使用。在使用 iOS SDK 14 之前,这一切正常。当开始使用 iOS sdk 15 时,UITableView 在滚动时出现错误。
错误是“断言 UITableView 内部不一致 prefetchedCells 和 indexPathsForPrefetchedCells 不同步”
由于这个错误,单元格开始随机消失。
此断言表明 UITableView 内部状态已“损坏”。最常见的原因是表视图正在执行更新或重新加载,并且正在回调数据源或委托方法之一,并且您的代码以某种方式导致 UITableView 上出现意外的“重入”(例如,通过执行从此回调内部进行另一个更新/重新加载或手动运行主运行循环)。这会导致 UITableView 进入不一致的内部状态,因为它已经在处理另一个更新。
就我而言,UITableView 和使用 SwiftSoup 将 html 转换为 attributeString 的 NSAttributedString() init 方法之间的交互很糟糕。它在更新 tableViewCell 时被调用,这导致 cellForRowAt 再次被调用,而我的应用程序代码已经在处理 cellForRowAt 调用。之后 tableView 就失去了理智。
我通过在 cellForRowAt 运行之前将 html 转换为 attributeString 来修复此问题,然后 cellForRowAt 使用它。
我也面临这个问题。找了好久,找到了这个视频:
Apple 所做的一些性能改进打破了我使用的嵌套 UITableView。
我将UITableView的
isPrefetchingEnabled
的值更改为false
。您可以将其应用于特定的 TableView,也可以为整个应用程序更改它。
if #available(iOS 15.0, *) {
UITableView.appearance().isPrefetchingEnabled = false
}
当单元格的完全相同的实例呈现到同一个表中的两个不同行时,可能会发生这种情况。在我看到的情况下,相同的单元格实例作为第一行添加到两个不同的部分。
主要问题不在于直接使用html到属性字符串的转换。该案例是关于在表重新加载时冻结主线程的。 人们可以检查甚至空数据转换为属性字符串
public init(data:options:documentAttributes:) throws
持续时间太长了。
因此,为了避免出现问题和冻结,应该为字符串创建缓存并在非主线程上进行转换。
// int-string dictionary cache
private var attributedStringCache = [Int: NSAttributedString]()
// some conversion function
private func attributedString(html string: String) -> NSAttributedString? {
...
return attributedString
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCellReuseId", for: indexPath)
let htmlString = someDataSource[indexPath]
let hashValue = htmlString.hashValue
var attributedText = attributedStringCache[hashValue]
if attributedText == nil {
DispatchQueue.global(qos: .userInteractive).async {
attributedText = self.attributedString(html: htmlString)
DispatchQueue.main.async {
self.attributedStringCache[hashValue] = attributedText
UIView.performWithoutAnimation() {
tableView.reloadRows(at: [indexPath], with: .none)
}
}
}
}
cell.textLabel?.attributedText = attributedText
}