天天看點

ios整理(六)關于用富文本在tableview的cell去加載html字元串的優化方案

ios整理(六)關于用富文本在tableview的cell去加載html字元串的優化方案

1.相信用iOS系統的類去加載html字元串很多人第一反應就是

NSString *contens = @"1231我給你數

點這裡

";

NSData *data = [contens dataUsingEncoding:NSUnicodeStringEncoding];

NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};

NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];

然後後面的就是直接将attr這個對象指派給lab或者textView這樣的控件就能展示了,蘋果提供的API就是這個。

然而我要說的是在反複的intiWithData的時候它是比較耗費記憶體性能的,你可以嘗試的去把他放在tableview裡面的cell去加載,你會發現滾動起來後通過cell複用機制去加載會使UI界面變得卡頓,那麼為什麼會造成這種原因呢?通過反複的去驗證,我發現反複的intiWithData确實挺爆記憶體的,後來就找原因。

網上也看過别人寫的一個優化的方案,很直接的就是你可以異步開辟子線程去加載這個attr然後在主線程去指派,這樣就可以了。

複制代碼

// 擷取全局并發隊列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 擷取主隊列

dispatch_queue_t mainQueue = dispatch_get_main_queue();

dispatch_async(queue, ^{

contents = [contents stringByReplacingOccurrencesOfString:@"\n" withString:@"<br>"];
NSData *data = [content dataUsingEncoding:NSUnicodeStringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
[attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17] range:NSMakeRange(0, attr.length)];
//回主線程重新整理ui
dispatch_async(mainQueue, ^{
     //給UI控件指派
     self.lab.attr = attr;
});           

});

類似于這種,可以減少記憶體使用率讓UI不卡頓。但是這種情況下你要考慮是否适合目前的場景,例如你建立的這個cell是根據富文本裡面的高度去計算的,那麼你就得仔細考慮一下了,上面這段代碼是通過異步進行加載的,那麼的話你要計算出高度的話就得異步去拿高度,但是當異步拿到高度的時候你cell很有可能已經建立完了,時機沒辦法同步。而且當你高度拿到後再進行reloadData重新整理的話,那麼整個tableview是會重新布局的,那麼又會去重新計算,這樣會出現閃屏的現象,那麼廢話說了那麼,原因就是因為它加載的時候轉換的contens内容不多或者隻initWithData一兩次還好,但是cell的滾動複用會讓他多次加載,是以不能放在cell建立的時候去執行。

下面是我個人的思路,有其他想法的可以提出來一起交流:

1.如果cell裡面加載會反複執行這段代碼的話,就會消耗記憶體及卡頓UI,那麼我在cell建立前提前做好這個事情,讓他不需要initWithData多次。

在模型的.h裡面建立attr屬性

@interface TestModel : NSObject

@property (strong,nonatomic) NSMutableAttributedString *attr;

@end

在.m裡去做剛才的這一步,那麼就是說當請求資料結束後再進行富文本的轉換在指派給模型儲存,而不是建立cell的時候去加載富文本

  • (instancetype)initModelWithDict:(NSDictionary *)dict {

    //初始化

    id obj = [[self alloc] init];

    //字典轉模型

    [obj setValuesForKeysWithDictionary:dict];

    //轉富文本

    if (contens) {

    NSData *data = [contens dataUsingEncoding:NSUnicodeStringEncoding];
    NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
    NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
    [attr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:17] range:NSMakeRange(0, attr.length)];
    model.attr = attr;           

    }

    return obj;

那麼,模型走完這一步再去重新整理reloadData 那麼cell加載的時候就可以直接将model裡的attr給cell裡面的lab或者textView控件的attr就行了,每次就是從模型裡面去取值,這樣性能就會好點。

後面要計算高度可以沖模型裡面取到attr對象,然後根據lab或者textView調用系統的計算布局就行,下面的經供參考

CGFloat labH = [self.lab boundingRectWithSize:CGSizeMake(375, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attr context:nil].size.height;

原文位址

https://www.cnblogs.com/wm941142146/p/10653266.html

繼續閱讀