Swift:使用nsattributestring.DocumentType.HTML在标签中显示HTML数据

Swift:使用nsattributestring.DocumentType.HTML在标签中显示HTML数据,html,ios,swift4,Html,Ios,Swift4,我使用NSAttributeString.DocumentType.html在tableview单元格的多个标签上显示html格式的字符串,如下所示 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell")!

我使用NSAttributeString.DocumentType.html在tableview单元格的多个标签上显示html格式的字符串,如下所示

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell")!

     let htmlDescription = try! NSAttributedString(
            data: self.Structures[indexPath.section].description.data(using: .unicode, allowLossyConversion: true)!,
            options:[.documentType: NSAttributedString.DocumentType.html,
                     .characterEncoding: String.Encoding.utf8.rawValue],
            documentAttributes: nil)

             cell.textLabel?.numberOfLines = 0
             cell.textLabel?.attributedText = htmlDescription

    return cell

}

这项工作与预期的一样,但是速度非常慢,在操作完成之前,视图似乎处于冻结状态。这对于生产级工作来说是可怕的。我的问题是如何优化它以防止冻结?

是的,不幸的是,当使用本机iOS API时,HTML呈现非常慢。我遇到了完全相同的问题,试图用基于HTML数据的单元格内容填充表视图。我做了很多测试和研究,试图找到一个更快的解决方案,但没有找到更好的

最后,我使用了一个带有队列的解决方案,该队列将HTML呈现为一个图像,然后在准备就绪时用它更新表视图单元格。如果选择此解决方案,有几件事需要注意

大部分工作不能在后台线程中完成,因为执行转换的NSAttributeString函数明确要求它在主线程上操作。其目的是使作品系列化。 后台队列需要限制不吃饭的工人数量 占用太多内存和CPU。试着从一两个开始。 您需要检测渲染何时完成,以拍摄快照,至少在我的情况下,这是相当棘手的。如果您使用UILabel,可能问题不大,但WkWebView和UIWebView的问题更大,因为它们在这方面存在问题。 渲染时,您需要将占位符图像放入单元格中,最好与生成的图像大小相同。如果具有动态单元高度,则需要在渲染完成时更新高度。这将增加复杂性。 此解决方案可能不会加快渲染速度,但至少会大大提高响应速度,因为它不会像将HTML放入每个单元格那样占用主线程。
虽然这是一个相当复杂且远不是最优的解决方案,但它确实将我的应用程序从无法使用的状态改进为相当好的状态。如果有人有更好的解决方案,我会洗耳恭听。

我也遇到过类似的问题。虽然@LGP解决方案可能适合您,但我已经有了一个不那么棘手的解决方案,这对您也可能足够了。在我的例子中,真正低效的是将HTML解析为NSAttributedString。即使在@LGP的解决方案中也必须发生这种情况

我使用了一种非常简单的方法——当我从后端加载数据时,作为解析响应的一部分,我还解析了HTML。当然,这使得后端调用更加冗长,但是模型本身已经包含NSAttributedString,而不是需要解析的字符串

如果你尝试一下,你的牢房将看起来像这样,但我想从我试图解释的内容中可以清楚地看出:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell")!

    let htmlDescription = self.Structures[indexPath.section].attributedDescription
    cell.textLabel?.numberOfLines = 0
    cell.textLabel?.attributedText = htmlDescription
    return cell
}
这将使表的呈现对资源的要求更少,速度更快。在我的例子中,延迟滚动和平滑滚动是不同的

当然,在这种情况下,在模型解析过程中,您必须使用:

self.attributedDescription = try! NSAttributedString(
        data: description.data(using: .unicode, allowLossyConversion: true)!,
        options:[.documentType: NSAttributedString.DocumentType.html,
                 .characterEncoding: String.Encoding.utf8.rawValue],
        documentAttributes: nil)

你的方法很有趣。仍然使用这种方法,将模式解析逻辑移动到DispatchQueue并显示进度指示器的可视指示器会有什么效果?在DispatchQueue上运行此命令有任何问题吗?@JamesWahome它始终在DispatchQueue上运行。。你是说在背景线上吗?如果是这样,可能会更好,但我仍然建议在获得数据时只做一次,而不是在cellForRowAt中,因为这显然只是浪费资源。。如果您在后台线程上运行它,那么您必须提供一些同步逻辑,以确保它与单元格布局正常工作……是的,我的意思是在后台线程上,是的,只有在数据被提取时,而不是在cellForRowAt@JamesWahome好啊NSAttributedString的文档明确指出,除了主线程之外,您不能在任何其他线程上执行HTML解析。请参阅中的讨论部分,因此,正如它所述,您可能会遇到超时和失败。因此,您必须将它保持在主线程上,它才能工作