NSAttributedString中的HTML渲染非常慢

时间:2015-08-06 09:57:39

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

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

以下是探查器的快照。

enter image description here

我试图将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()
      })
   })

看起来如下 enter image description here

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

谢谢!

更新:

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

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

1 个答案:

答案 0 :(得分:12)

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

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

Before

紧接着:

enter image description here

所以你可以想象,有时需要几乎一秒的时间来开始这一切。 后续调用要快得多。我的解决方法是在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