iOS直播間聊天室—圖文混排加載網(wǎng)絡(luò)圖片(含Demo)

Question:

1.刷新直播間消息機(jī)制該用哪種方法?哪一種更加合適?

2.聊天室該如何圖文混排?

3.聊天室出現(xiàn)特殊字符臨界點(diǎn)不換行?高度計(jì)算錯(cuò)誤?

4.聊天室該如何加載網(wǎng)絡(luò)圖片?

5.聊天室如何優(yōu)化?

6.交互時(shí)刷新消息經(jīng)常出現(xiàn)越界情況,導(dǎo)致崩潰?

7.聊天室出現(xiàn)阿拉伯文&中文&數(shù)字&英文等類似情況如何處理?

...

以上這些問(wèn)題我相信做過(guò)聊天室直播間的肯定或多或少遇到過(guò),那么本編文章就為了解決這些問(wèn)題而來(lái),底部提供Demo??。

1.刷新直播間消息機(jī)制該用哪種方法?哪一種更加合適?

聊天室刷新分為兩種:
一:采用來(lái)一條消息刷新一條消息,適用于小主播和人氣較少的直播間。優(yōu)點(diǎn)就是可以快速的查看到發(fā)言記錄,給人絲滑流暢感,缺點(diǎn)就是刷新過(guò)于頻繁,消耗性能。


image.png
直接刷新.gif

二:定時(shí)刷新,適用于大主播或某段活動(dòng)時(shí)間內(nèi)用戶發(fā)言特別頻繁時(shí)間段,假設(shè)一秒鐘接收到幾十條消息時(shí)你直接一條條刷新是毫無(wú)意義的,不僅影響性能而且用戶也看不清。所以這種情況可以選擇弄個(gè)定時(shí)器,每0.5秒刷新一次。至于多久刷新一次,你可以根據(jù)主播人氣,觀看人數(shù),發(fā)言速度來(lái)調(diào)整。


image.png
0.5秒刷新一次.gif

通過(guò)對(duì)比,二者都是每秒接收到30條消息時(shí),一條條刷新和定時(shí)刷新所消耗的性能非常明顯。
如何選擇,各位自行斟酌。

2.聊天室該如何圖文混排?

如果在子線程生成我們的富文本,這個(gè)時(shí)候你肯定不可以在子線程創(chuàng)建UIimageView這些,然后轉(zhuǎn)UIimage,我個(gè)人有幾個(gè)技巧:
一:聊天肯定會(huì)帶有等級(jí)系列,拿我的直播來(lái)說(shuō),現(xiàn)在有0-100級(jí),我個(gè)人寫了一個(gè)等級(jí)生成器,通過(guò)業(yè)務(wù)生成每個(gè)等級(jí)段所對(duì)應(yīng)文字+圖片+等級(jí)+漸變色形成view,然后我們啟動(dòng)APP時(shí),通過(guò)view轉(zhuǎn)image,內(nèi)存就會(huì)保存有0-100張圖片,所占300k左右而已。那么下次用的時(shí)候,直接傳入等級(jí)獲取對(duì)應(yīng)的UIimage。

+ (instancetype)sharedInstance {
    static EWLevelManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[EWLevelManager alloc] init];
        instance.data = [NSMutableDictionary dictionary];
    });
    return instance;
}

- (void)setup {
    [self.data removeAllObjects];
    
    for (NSInteger i = 0; i <= 100; i++) {
        // NDLeveBgView就是我的等級(jí)生成器,返回view
        // 啟動(dòng)app我們調(diào)用一次這個(gè)方法,然后內(nèi)存就有生成0-100等級(jí)圖片
        NDLeveBgView *view = [[NDLeveBgView alloc] init];
        view.frame = CGRectMake(0, 0, 30.0, 14.0);
        view.layer.cornerRadius = 2;
        view.layer.masksToBounds = YES;
        view.isShadeLv = YES;
        view.level = i;
        
        [self.data setObject:[self convertCreateImageWithUIView:view] forKey:[NSString stringWithFormat:@"%li", (long)i]];
    }
    
//    NSMutableData *data = [[NSMutableData alloc]init];
//    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
//    [archiver encodeObject:self.data forKey:@"talkData"];
//    [archiver finishEncoding];
//    NSLog(@"查看byte = %lu", (unsigned long)data.length);
}

- (UIImage *)imageForLevel:(NSInteger)Level {
    return [self.data objectForKey:[NSString stringWithFormat:@"%li", (long)Level]];
}


/** 將 UIView 轉(zhuǎn)換成 UIImage */
- (UIImage *)convertCreateImageWithUIView:(UIView *)view {
    
    //UIGraphicsBeginImageContext(view.bounds.size);
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, [UIScreen mainScreen].scale);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [view.layer renderInContext:ctx];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;
}

至于圖片如何轉(zhuǎn)富文本我就不多贅述了,這種沒(méi)啥可說(shuō)的,都在demo中。

3.聊天室出現(xiàn)特殊字符臨界點(diǎn)不換行?高度計(jì)算錯(cuò)誤?

我想肯定有人遇到過(guò)這個(gè)問(wèn)題,當(dāng)我們使用UILabel時(shí),根據(jù)消息生成的富文本,高度計(jì)算得明明很正確,但就是不換行!!當(dāng)我們?cè)跍y(cè)試的時(shí)候明明運(yùn)行一切都正常,但是到了線上就出現(xiàn)不換行,高度計(jì)算錯(cuò)誤等等系列問(wèn)題。

我可以很明確的告訴大家,這就是UILabel的問(wèn)題,他在不同系統(tǒng)版本表現(xiàn)不一樣,經(jīng)過(guò)我多次測(cè)試,曾經(jīng)一度讓我懷疑是不是我的問(wèn)題,但是后來(lái)我換了YYLabel后,一切都清凈了,所以拋棄UILabel吧,它在表達(dá)復(fù)雜的文本時(shí),總是不那么如意。
跟我說(shuō)一句:YYKit牛逼???。。?/p>

可能有同學(xué)反駁,其實(shí)我也想證明是我的問(wèn)題,如果有同學(xué)用UILabel做的直播間聊天室,希望不吝賜教。

4.聊天室該如何加載網(wǎng)絡(luò)圖片?

這個(gè)問(wèn)題其實(shí)也好解決。
當(dāng)我們生成禮物消息富文本時(shí),先用禮物縮略的占位圖替代,同時(shí)使用SD下載該圖片,下載完了以后重新生成該富文本,接著通過(guò)代理回調(diào)去刷新該cell。

case NDSubMsgType_Gift_Text: {   // 禮物彈幕(文本)消息
            // 下載標(biāo)簽圖片
            [self downloadTagImage];
            // 下載禮物圖片
            [self downloadGiftImage];
            self.bgColor = NormalBgColor;
            [self Gift_Text];
        }
            break;

/** 下載禮物縮略圖 */
- (void)downloadGiftImage {
    NSString *urlStr = self.msgModel.giftModel.thumbnailUrl;
    if (!urlStr || urlStr.length < 1) {
        return;
    }
    if (self.finishDownloadGiftImg) {
        return;
    }
    self.finishDownloadGiftImg = YES;
    
    // 1. 如果本地有圖片
    self.giftImage = [self cacheImage:urlStr];
    if (self.giftImage) {
        return;
    }
    
    // 2. 下載遠(yuǎn)程圖片
    NSURL *url = [NSURL URLWithString:urlStr];
    EWWeakSelf
    id sdLoad = [[SDWebImageManager sharedManager] loadImageWithURL:url options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
        
    } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
        if (image){
            // 刷新UI
            weakSelf.giftImage = image;
            // 更新屬性文字
            [weakSelf downloadTagImageFinish];
        }
    }];
    [self.tempLoads addObject:sdLoad];
}

- (void)downloadTagImageFinish {
    // 更新屬性文字
    [self msgUpdateAttribute];
    // 通知代理刷新屬性文字
    if (self.delegate && [self.delegate respondsToSelector:@selector(attributeUpdated:)]) {
        [self.delegate attributeUpdated:self];
    }
}

/** 消息屬性文字發(fā)生變化(更新對(duì)應(yīng)cell) */
- (void)msgAttrbuiteUpdated:(NDMsgModel *)msgModel {
    NSInteger row = [self.msgArray indexOfObject:msgModel];
    if (row >= 0) {
        [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:row inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
        if (row == self.msgArray.count - 1) {
            [self scrollToBottom:YES];
        }
    }
}

以上代碼都是關(guān)鍵部分,更詳細(xì)可以對(duì)照demo。

5.聊天室如何優(yōu)化?

聊天室的優(yōu)化其實(shí)也就是UITableView的優(yōu)化:

一:我們所有的cell通過(guò)復(fù)用,每一種消息類型對(duì)應(yīng)不同cell。


image.png

二:所有的消息所需要的背景顏色,富文本,高度等等都用模型記錄。


image.png

三:cell高度緩存,每次都從我們的模型讀取,更加高效快捷。

6.交互時(shí)刷新消息經(jīng)常出現(xiàn)越界情況,導(dǎo)致崩潰?

崩潰的原因大多數(shù)都在同時(shí)對(duì)同一個(gè)數(shù)組操作、插入indexPaths出現(xiàn)問(wèn)題等。
一:如何保證同一時(shí)間數(shù)組只執(zhí)行一種操作?
加鎖
鎖有好多種,有自旋鎖、信號(hào)量、遞歸鎖、互斥鎖等等
自旋鎖性能最高,但是經(jīng)過(guò)蘋果確認(rèn)是有問(wèn)題存在的,所以你可以選擇其他類型。
這里我選擇的是互斥鎖:

#pragma mark - 消息追加
- (void)addNewMsg:(NDMsgModel *)msgModel {
    if (!msgModel) return;
    
    pthread_mutex_lock(&_mutex);
    // 消息不直接加入到數(shù)據(jù)源
    [self.tempMsgArray addObject:msgModel];
    pthread_mutex_unlock(&_mutex);
    
    if (_reloadType == NDReloadLiveMsgRoom_Direct) {
        [self tryToappendAndScrollToBottom];
    }
}

/** 追加數(shù)據(jù)源 */
- (void)appendAndScrollToBottom {
    if (self.tempMsgArray.count < 1) {
        return;
    }
    pthread_mutex_lock(&_mutex);
    // 執(zhí)行插入
    .....代碼塊
    
    pthread_mutex_unlock(&_mutex);
    
   ...代碼塊

//清空消息重置
- (void)reset {
    pthread_mutex_lock(&_mutex);
    
    ...代碼塊
    pthread_mutex_unlock(&_mutex);
}
}

更多詳見(jiàn)demo。

二:插入indexPaths出現(xiàn)越界問(wèn)題,其實(shí)這個(gè)問(wèn)題的產(chǎn)生也是因?yàn)槲覀儗?duì)數(shù)組同時(shí)操作而導(dǎo)致的,如果你解決了數(shù)組的問(wèn)題,那么這個(gè)問(wèn)題也迎刃而解。

7.聊天室出現(xiàn)阿拉伯文&中文&數(shù)字&英文等類似情況如何處理?

這個(gè)問(wèn)題非常有意思!具體可參考這篇文章
因?yàn)榘⒗?、希臘文等系列語(yǔ)言是強(qiáng)語(yǔ)言,并且從右向左排列,而我們的中文也屬于強(qiáng)語(yǔ)言,但是從左向右排列。當(dāng)這二者碰撞到一起會(huì)怎么樣呢?
到底是遵從我們的規(guī)則還是遵從阿拉伯文的規(guī)則?

我這里做的是強(qiáng)制按照中文規(guī)則排版。

// 強(qiáng)制排版(從左到右)
    attribute.yy_baseWritingDirection = NSWritingDirectionLeftToRight;
    attribute.yy_writingDirection = @[@(NSWritingDirectionLeftToRight | NSWritingDirectionOverride)];

// 強(qiáng)制排版(從左到右)
    paraStyle.alignment = NSTextAlignmentLeft;
    paraStyle.baseWritingDirection = NSWritingDirectionLeftToRight;

如果大家覺(jué)得有什么問(wèn)題的,可以評(píng)論指出。

最后就是我們的demo了,如果覺(jué)得可以的希望點(diǎn)個(gè)star哦,Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,026評(píng)論 4 61
  • 期待了兩個(gè)星期的“好嗎好的”民謠音樂(lè)會(huì)終于如期舉行。在這期間我的心情為:期待—失落—重燃希望—欣喜同時(shí)又有點(diǎn)愧疚。...
    瑤小瑤18閱讀 305評(píng)論 0 2
  • 我把陽(yáng)光存起來(lái) 寄給有需要的人 我把生命存起來(lái) 寄給有需要的人 我把幸福存起來(lái) 寄給有需要的人 我把善良存起來(lái) 寄...
    英雄拒絕黃昏閱讀 319評(píng)論 0 3
  • 月光傾瀉,清涼如水。披上一件外衣足以抵擋這凜冽。時(shí)光前進(jìn)后退,透明玻璃的裂痕寸寸入我心。我在等什么?伸出手游絲般的...
    是咕咚哦閱讀 242評(píng)論 0 0

友情鏈接更多精彩內(nèi)容