NSAttributedString中的HTML渲染非常慢 [英] Very slow HTML rendering in NSAttributedString

查看:571
本文介绍了NSAttributedString中的HTML渲染非常慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have UITableView with dynamic sizing cells that displays list of comments in HTML format and I faced with the problem that NSAttributedString renders HTML content extremely slow!

这是来自探查器的快照。

Here is snapshot from profiler.

我试图将NSAttributedString初始化分开线程,但仍然很慢,用户在呈现HTML时看到空单元格,最后在完成呈现单元格时,布局不正确。

I tried to put the NSAttributedString initialization to separate thread, but still slow and user sees empty cells while HTML is being rendered and finally when it finished rendering cell is not layout properly.

    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()
      })
   })

关注

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

Please advice how to speed up rendering and fix cell layout.

谢谢!

更新:

解决了细胞委托和标志,表明归因于字符串已初始化。也许会帮助某人:

Solved with cell delegate and flag indicating that attributed string is initialized. Maybe would help somebody:

// 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
}


推荐答案

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

ABout the slow parsing of the HTML into a string: The first time you create an attributed string of HTML, iOS creates all sorts of extra threads needed to parse the string, among which JavascriptCore engine.

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

Before parsing the first NSAttributedString from HTML:

紧接着:

所以你可以想象,有时需要几乎一秒的时间来开始这一切。
后续调用要快得多。我的解决方法是解析Appdelegate中的应用程序:didFinishingLaunchingWithOptions:函数中的HTML,以便在需要时我在内存中拥有所有必需的框架(Objective-C):

So you can imagine it takes almost a second sometimes to start this all up. Subsequent calls are much faster. My workaround was to parse HTML in the application:didFinishingLaunchingWithOptions: function in the Appdelegate, so that I had all necessary frameworks in memory when needed (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;
}

另见这个答案

这篇关于NSAttributedString中的HTML渲染非常慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆