使用NSAttributedString的单元格会使UITableView滚动变慢。

4
我有一个表格视图,其中包含多种类型的单元格。其中之一是带有TextView的单元格,在这个文本视图中,我必须从数据中呈现NSAttributedString。根据Apple documentation,必须在主线程上执行此操作:

HTML导入程序不应从后台线程调用(即选项字典包括值为NSHTMLTextDocumentType的NSDocumentTypeDocumentAttribute)。它将尝试与主线程同步,失败并超时。在主线程中调用它可以运行(但如果HTML包含对外部资源的引用,则仍可能超时,应尽量避免)。HTML导入机制旨在实现类似于Markdown的东西(即文本样式、颜色等),而不是用于一般的HTML导入。

但是以这种方式呈现会使表格视图滚动出现卡顿,并且还会影响自动布局。这是我的单元格内部的代码。
dispatch_async(dispatch_get_main_queue(), ^{
    NSString* htmlString = [NSString stringWithFormat:@"<div style=\"font-family:%@; font-size:%dpx; color:#08080d;\">%@</div>",fontNameBase, 16,txt];
    htmlString = [Utility replaceHtmlCodeEntities:htmlString];
    NSData* tempData = [htmlString dataUsingEncoding:NSUnicodeStringEncoding];
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:tempData  options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
    self.textViewMsg.attributedText = txt;
});

我这样滚动我的tableView:
-(void)reloadAndScroll{
    [self.tableChat reloadData];

    long lastRowNumber = [_tableChat numberOfRowsInSection:0] - 1;
    if (lastRowNumber > 0) {
        NSIndexPath* indexPath = [NSIndexPath indexPathForRow:lastRowNumber inSection:0];
        [_tableChat scrollToRowAtIndexPath:indexPath        
        atScrollPosition:UITableViewScrollPositionBottom animated:NO];
    }
}

有没有其他方法可以创建一个带属性的字符串而不会出现这些问题?

那个崩溃的描述是什么? - Rameez
@Rameez 应用程序因未捕获的异常 'NSInternalInconsistencyException' 被终止,原因:'仅在主线程上运行!' - tara tandel
好的。这意味着你的所有代码都必须在主线程上运行。所以我有一个快速建议给你。不要每次都创建属性字符串。一旦创建了属性字符串,请将该字符串存储到您的模型中。因此,当下一次表视图重新加载您的单元格时,从您的模型中选择已经创建的字符串。 - Rameez
@Rameez,这是聊天表格,所以对于新消息,我必须立即呈现。 - tara tandel
@taratandel 没问题。您只需在模型中维护一个标志,用于指示消息的属性字符串是否已经创建。如果消息的属性字符串已经创建,则从您的模型中获取;否则,请创建它。 - Rameez
显示剩余3条评论
1个回答

7

我认为您需要在您的模型类中创建Attributed String,这样table view cell for row方法在滚动时就不会创建新的Attributed string,希望这可以帮助您,谢谢。

+(AttributedModel *)methodToGetAttributedDetail :(NSString *)txt {

    AttributedModel *objModel = [[AttributedModel alloc] init];

   NSString* htmlString = [NSString stringWithFormat:@"<div style=\"font-family:%@; font-size:%dpx; color:#08080d;\">%@</div>",fontNameBase, 16,txt];
   htmlString = [Utility replaceHtmlCodeEntities:htmlString];
   NSData* tempData = [htmlString dataUsingEncoding:NSUnicodeStringEncoding];
   NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:tempData  options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];

   objModel.attributedString  = attributedString;

   return objModel;
}

在tableView的CellforRow方法中使用此模型值。


你的意思是 modal 还是 model - Fogmeister
1
没错,模型和MVC方法一样,谢谢。 - Arjun hastir
为什么我应该返回整个模型?你这样做有特定的原因吗? - tara tandel
不需要,我只是展示一种模块化的方式,如果您有其他与此属性字符串相关的信息。 - Arjun hastir
我尝试了你的方法,但是出现了关于CFRunloop的崩溃。 - tara tandel
请问您能否分享代码,这样我就可以在我的端上进行调试了,谢谢。 - Arjun hastir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接