【问题标题】:Very slow HTML rendering in NSAttributedStringNSAttributedString 中的 HTML 渲染速度非常慢
【发布时间】:2015-08-06 09:57:38
【问题描述】:

我的 UITableView 带有动态调整大小的单元格,它以 HTML 格式显示 cmets 列表,我遇到了 NSAttributedString 呈现 HTML 内容非常慢的问题!

这是来自分析器的快照。

我尝试将 NSAttributedString 初始化放到单独的线程中,但仍然很慢,并且用户在呈现 HTML 时会看到空单元格,最后在完成渲染时单元格布局不正确。

    dispatch_async(GlobalQueue, {
       let html = NSAttributedString(
                    data: self.comment.htmlBody.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: false)!,
                    options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
                    documentAttributes: nil,
                    error: nil)

        dispatch_async(MainQueue, {
            self.commentLabel.attributedText = html
            self.commentLabel.font = UIFont(name: "HelveticaNeue-Light", size: 14.0)!

            if let writer = self.comment.author {
                self.authorLabel.text = writer.name
            }

            self.layoutIfNeeded()
      })
   })

看起来如下

请建议如何加快渲染和修复单元格布局。

谢谢!

更新:

解决了单元格委托和标志,表明属性字符串已初始化。也许会帮助某人:

// TicketCell    
private var isContentInitialized = false
private var commentAttributedString:NSAttributedString?

var delegate: TicketCommentCellDelegate?
var indexPath: NSIndexPath!
var comment: TicketComment! {
    willSet {
        if newValue != self.comment {
            self.isContentInitialized = false
        }
    }
    didSet{
        self.configure()
    }
}

...
private func configure() {        
    if isContentInitialized {
        // here might be activity indicator stop
        ...
        if let writer = self.comment.author {
            self.authorLabel.text = writer.name
        }
    }
    else {
         // here might be activity indicator start

         dispatch_async(GlobalQueue, {
            self.commentAttributedString = NSAttributedString(
                                data: self.comment.htmlBody.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: false)!,
                                options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
                                documentAttributes: nil,
                                error: nil)                        

            self.isContentInitialized = true

            // here might be spinner stop
            dispatch_async(MainQueue, {
                self.delegate?.ticketCommentCellDidRenderCommentHTML(self)
            })
        })
    }
}

... 
protocol TicketCommentCellDelegate {
    func ticketCommentCellDidRenderCommentHTML(cell: TicketCommentCell)
}


// TableViewDataSource

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier(kTicketCommentCellIdentifier, forIndexPath: indexPath) as! TicketCommentCell

    cell.indexPath = indexPath
    cell.delegate = self
    cell.comment = self.rows[indexPath.section][indexPath.row]

    return cell
}

// MARK: - TicketCommentCellDelegate

func ticketCommentCellDidRenderCommentHTML(cell: TicketCommentCell) {
    self.tableView.reloadRowsAtIndexPaths([cell.indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}

// MARK: UITableViewDelegate

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {        
   var cell = self.commentCell

   cell.comment = self.rows[indexPath.section][indexPath.row]
   cell.setNeedsDisplay()
   cell.setNeedsLayout()

   let height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height + 1

    return height
}

【问题讨论】:

  • 你的内容有多大?
  • 不大,简单的邮件模板,一句话,一个段落的签名,还有几个href链接。约 1000 个字符
  • 没有从其他来源加载其他外部资源,例如 CSS 或 JavaScript?
  • 谢谢大家,解决了。更新了代码示例
  • 顺便说一句。模拟器解析 HTML 到 NSAttributedString 比实际设备慢很多,你可以自己试试

标签: ios swift uitableview grand-central-dispatch nsattributedstring


【解决方案1】:

关于将 HTML 解析为字符串的缓慢问题:第一次创建 HTML 的属性字符串时,iOS 会创建各种额外的线程来解析字符串,其中包括 JavascriptCore 引擎。

在从 HTML 解析第一个 NSAttributedString 之前:

紧接着:

因此,您可以想象有时启动这一切几乎需要一秒钟。 随后的调用要快得多。我的解决方法是在 Appdelegate 的 application:didFinishingLaunchingWithOptions: 函数中解析 HTML,以便在需要时在内存中拥有所有必要的框架(Objective-C):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSMutableAttributedString *attrStringFromHtml = [[NSMutableAttributedString alloc]
                                                     initWithData: [@"<span>html enabled</span>" dataUsingEncoding:NSUnicodeStringEncoding
                                                                                allowLossyConversion:NO]
                                                     options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}
                                                     documentAttributes:nil error:nil];
    NSLog(@"%@",[attrStringFromHtml string]);

    return YES;
}

另见this answer。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    相关资源
    最近更新 更多