iOS直播间聊天室遇到的问题

Question:

1.刷新直播间消息机制该用哪种方法?哪一种更加合适?

2.聊天室该如何图文混排?

3.聊天室出现特殊字符临界点不换行?高度计算错误?

4.聊天室该如何加载网络图片?

5.聊天室如何优化?

6.交互时刷新消息经常出现越界情况,导致崩溃?

7.聊天室出现阿拉伯文&中文&数字&英文等类似情况如何处理?

...

1.刷新直播间消息机制该用哪种方法?哪一种更加合适?

聊天室刷新分为两种:

一:采用来一条消息刷新一条消息,适用于小主播和人气较少的直播间。优点就是可以快速的查看到发言记录,给人丝滑流畅感,缺点就是刷新过于频繁,消耗性能。

image

二:定时刷新,适用于大主播或某段活动时间内用户发言特别频繁时间段,假设一秒钟接收到几十条消息时你直接一条条刷新是毫无意义的,不仅影响性能而且用户也看不清。所以这种情况可以选择弄个定时器,每0.5秒刷新一次。至于多久刷新一次,你可以根据主播人气,观看人数,发言速度来调整。

image

通过对比,二者都是每秒接收到30条消息时,一条条刷新和定时刷新所消耗的性能非常明显。

如何选择,各位自行斟酌。

2.聊天室该如何图文混排?

如果在子线程生成我们的富文本,这个时候你肯定不可以在子线程创建UIimageView这些,然后转UIimage,我个人有几个技巧:

一:聊天肯定会带有等级系列,拿我的直播来说,现在有0-100级,我个人写了一个等级生成器,通过业务生成每个等级段所对应文字+图片+等级+渐变色形成view,然后我们启动APP时,通过view转image,内存就会保存有0-100张图片,所占300k左右而已。那么下次用的时候,直接传入等级获取对应的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就是我的等级生成器,返回view

        // 启动app我们调用一次这个方法,然后内存就有生成0-100等级图片

        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 转换成 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;

}

3.聊天室出现特殊字符临界点不换行?高度计算错误?

我想肯定有人遇到过这个问题,当我们使用UILabel时,根据消息生成的富文本,高度计算得明明很正确,但就是不换行!!当我们在测试的时候明明运行一切都正常,但是到了线上就出现不换行,高度计算错误等等系列问题。

我可以很明确的告诉大家,这就是UILabel的问题,他在不同系统版本表现不一样,经过我多次测试,曾经一度让我怀疑是不是我的问题,但是后来我换了YYLabel后,一切都清净了,所以抛弃UILabel吧,它在表达复杂的文本时,总是不那么如意。

跟我说一句:YYKit牛逼🐂!!!

可能有同学反驳,其实我也想证明是我的问题,如果有同学用UILabel做的直播间聊天室,希望不吝赐教。

4.聊天室该如何加载网络图片?

这个问题其实也好解决。

当我们生成礼物消息富文本时,先用礼物缩略的占位图替代,同时使用SD下载该图片,下载完了以后重新生成该富文本,接着通过代理回调去刷新该cell。


case NDSubMsgType_Gift_Text: { // 礼物弹幕(文本)消息

            // 下载标签图片

            [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\. 下载远程图片

    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];

    }

}

/** 消息属性文字发生变化(更新对应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];

        }     }  }

5.聊天室如何优化?

聊天室的优化其实也就是UITableView的优化:

一:我们所有的cell通过复用,每一种消息类型对应不同cell。

image

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

image

三:cell高度缓存,每次都从我们的模型读取,更加高效快捷。

6.交互时刷新消息经常出现越界情况,导致崩溃?

崩溃的原因大多数都在同时对同一个数组操作、插入indexPaths出现问题等。

一:如何保证同一时间数组只执行一种操作?

加锁

锁有好多种,有自旋锁、信号量、递归锁、互斥锁等等

自旋锁性能最高,但是经过苹果确认是有问题存在的,所以你可以选择其他类型。

这里我选择的是互斥锁:


#pragma mark - 消息追加

- (void)addNewMsg:(NDMsgModel *)msgModel {

    if (!msgModel) return;

    pthread_mutex_lock(&_mutex);

    // 消息不直接加入到数据源

    [self.tempMsgArray addObject:msgModel];

    pthread_mutex_unlock(&_mutex);

    if (_reloadType == NDReloadLiveMsgRoom_Direct) {

        [self tryToappendAndScrollToBottom];

    }

}

/** 追加数据源 */

- (void)appendAndScrollToBottom {

    if (self.tempMsgArray.count < 1) {

        return;

    }

    pthread_mutex_lock(&_mutex);

    // 执行插入

    .....代码块

    pthread_mutex_unlock(&_mutex);

  ...代码块

//清空消息重置

- (void)reset {

    pthread_mutex_lock(&_mutex);

    ...代码块

    pthread_mutex_unlock(&_mutex);

}

}

二:插入indexPaths出现越界问题,其实这个问题的产生也是因为我们对数组同时操作而导致的,如果你解决了数组的问题,那么这个问题也迎刃而解。

7.聊天室出现阿拉伯文&中文&数字&英文等类似情况如何处理?

这个问题非常有意思!具体可参考这篇文章

因为阿拉伯文、希腊文等系列语言是强语言,并且从右向左排列,而我们的中文也属于强语言,但是从左向右排列。当这二者碰撞到一起会怎么样呢?

到底是遵从我们的规则还是遵从阿拉伯文的规则?

我这里做的是强制按照中文规则排版。


// 强制排版(从左到右)

    attribute.yy_baseWritingDirection = NSWritingDirectionLeftToRight;

    attribute.yy_writingDirection = @[@(NSWritingDirectionLeftToRight | NSWritingDirectionOverride)];

// 强制排版(从左到右)

    paraStyle.alignment = NSTextAlignmentLeft;

    paraStyle.baseWritingDirection = NSWritingDirectionLeftToRight;

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容