6

Ho UITableView con celle di dimensionamento dinamiche che visualizza un elenco di commenti in formato HTML e ho affrontato il problema che NSAttributedString rende il contenuto HTML estremamente lento!Rendering HTML molto lento in NSAttributedString

Ecco la snapshot del profiler.

enter image description here

Ho provato a mettere l'inizializzazione NSAttributedString a thread separato, ma ancora lento e utente vede celle vuote mentre HTML viene reso infine quando è finito il rendering cella non Layout correttamente.

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

Sembra seguente enter image description here

Si prega di consulenza come accelerare il rendering e correggere il layout delle cellule.

Grazie!

UPDATE:

risolto con delega cellulare e flag che indica che stringa attribuito viene inizializzata. Forse avrebbe aiutato qualcuno:

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

Quanto è grande il contenuto? – holex

+0

Modello di e-mail non grande, semplice, una frase, firma su un paragrafo con alcuni link href. Circa 1000 caratteri – Madman

+0

nessun'altra risorsa esterna viene caricata da qualche altra fonte, come _CSS_ o _JavaScript_? – holex

risposta

9

per il lento parsing del codice HTML in una stringa: La prima volta che si crea una stringa attribuito di HTML, iOS crea ogni sorta di fili supplementari necessari per analizzare la stringa, tra i quali JavaScriptCore motore.

Prima l'analisi del primo NSAttributedString da HTML:

Before

E subito dopo:

enter image description here

Così si può immaginare che ci vuole quasi un secondo a volte per iniziare questo tutto in su. Le chiamate successive sono molto più veloci. La mia soluzione era quella di analizzare HTML nella funzione application:didFinishingLaunchingWithOptions: nel AppDelegate, in modo che ho avuto tutte le strutture necessarie in memoria quando necessario (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; 
} 

vedere anche this answer.