6

У меня есть UITableView с динамическими ячейками размера, который отображает список комментариев в формате HTML, и я столкнулся с проблемой, что NSAttributedString делает HTML-контент чрезвычайно медленным!Очень медленный рендеринг HTML в NSAttributedString

Это снимок от профилировщика.

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 
} 
+0

, как большой ваш контент? – holex

+0

Не большой, простой шаблон электронной почты, одно предложение, подпись об одном абзаце с несколькими ссылками href. Около 1000 символов – Madman

+0

другие внешние ресурсы не загружаются из какого-либо другого источника, например _CSS_ или _JavaScript_? – holex

ответ

9

ABout медленного разбора HTML в строку: В первый раз, вы создаете приписываемую строку HTML, IOS создает все виды дополнительных потоков, необходимых для разбора строки, среди которых JavaScriptCore двигатель.

Перед разборе первый NSAttributedString из HTML:

Before

И сразу же после того, как:

enter image description here

Таким образом, вы можете себе представить, это занимает почти второй иногда, чтобы начать все это вверх. Последующие вызовы намного быстрее. Мой обходной путь был для разбора HTML в application:didFinishingLaunchingWithOptions: функции в AppDelegate, так что у меня были все необходимые рамки в памяти, когда это необходимо (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.

Смежные вопросы