问题描述
观看直播情况下,直播间五百人同时发送消息,聊天界面展示会很耗性能,影响直播视频正常播放
分析和解决方案
1.聊天接收时,收到的代理方法会传递一个字典,这个字典包含这条聊天的所有信息,但是接收到这个消息后,我这边没有任何处理,直接把这个东西交给我的DataSourceManager去处理,然后将解析过的lastObject给chatView去添加cell。
这个时候就造成一个问题,如果一秒钟我这边接收到了100条消息,我这个流程就要走100次,然后在TableView中reload100次。
为了避免这个问题,可以在接收到这个消息后,进行一些处理,如果每秒钟发送多条消息,就将这些消息打包,然后交给chatView直接添加这个数组就可以了
下面是处理每秒钟加载过多消息进行的限制
//解析公聊消息
WS(ws)
[self.manager addPublicChat:dic userDic:self.userDic viewerId:self.viewerId groupId:self.groupId danMuBlock:^(NSString * _Nonnull msg) {
//弹幕
[ws.playerView insertDanmuString:msg];
}];
//判断时间
NSString *publistTime = dic[@"time"];
NSInteger publish = [NSString timeSwitchTimestamp:publistTime andFormatter:@"HH:mm:ss"];
if (_lastTime == publish) {
//添加数组
[self.chatArr addObject:[self.manager.publicChatArray lastObject]];
// NSLog(@"同一秒,添加至数组");
[_updateTimer invalidate];
WS(weakSelf)
_updateTimer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:NO block:^(NSTimer * _Nonnull timer) {
if (weakSelf.chatArr.count != 0) {
[weakSelf.chatView addPublicChatArray:weakSelf.chatArr];
[weakSelf.chatArr removeAllObjects];
// NSLog(@"延迟数据校对");
}
}];
}else{
if (self.chatArr.count != 0) {
[self.chatView addPublicChatArray:self.chatArr];
[self.chatArr removeAllObjects];
// NSLog(@"将数组中的元素添加至消息中");
}
[self.chatView addPublicChat:[self.manager.publicChatArray lastObject]];
_lastTime = publish;
// NSLog(@"+++++++++++++++++");
}
到这里解决了一个问题,当每秒钟消息过多,让他只走了一遍reloadData
2.优化到这里后,iphone7及以上机型播放直播视频加五百人聊天已经不卡顿了,但是在iphone6 iphone6plus 还是有轻微卡顿,而且卡顿还是1S一卡顿,和我这个延迟机制刚好相对应
ChatView中处理添加数组方法
/**
添加一个聊天数组(直播公聊如果每秒钟发送消息过多,会调用这个方法)
@param array 聊天数组
*/
-(void)addPublicChatArray:(NSMutableArray *)array{
if([array count] == 0) return;
NSInteger preIndex = [self.publicChatArray count];
[self.publicChatArray addObjectsFromArray:[array mutableCopy]];
NSInteger bacIndex = [self.publicChatArray count];
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
for(NSInteger row = preIndex + 1;row <= bacIndex;row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(row-1) inSection:0];
[indexPaths addObject: indexPath];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.publicTableView reloadData];
//防止越界
NSIndexPath *lastIndexPath = [indexPaths lastObject];
if ((long)lastIndexPath.row > self.publicChatArray.count) {
return;
}
// [self.publicTableView beginUpdates];
// [self.publicTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
// [self.publicTableView endUpdates];
if (indexPaths != nil && [indexPaths count] != 0 ) {
[self.publicTableView scrollToRowAtIndexPath:[indexPaths lastObject] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
});
}
考虑到这个问题,也有可能是配置比较低的机型每秒钟加载数组过长,所以这里加了一个舍弃机制,这个数据过长的话就只加载最近的几条
//让每秒钟发送消息超过10条时,取最新的十条
if (array.count > 10 && self.input == YES ) {
// NSInteger count = array.count;
NSRange range = NSMakeRange(0, array.count - 10);
[array removeObjectsInRange:range];
// NSLog(@"每秒钟数据%d个,加载最新10条, 目前消息数%lu", count, self.publicChatArray.count);
}
3.优化了前面两个之后,有一个问题,我remove掉的那些数据是丢失了吗?如果我滑到顶部下拉刷新能不能查看之前的消息
下拉刷新机制
/**
下拉刷新新数据
*/
-(void)loadNewData{
/*
ChatViewDataSourceManager是一个数据处理中心单例,所有的消息要经过这个类去处理model,
并且这个数据中的聊天数组包含所有经过处理的聊天信息
*/
if ([ChatViewDataSourceManager sharedManager].publicChatArray.count > self.publicChatArray.count) {
NSMutableArray *arr = [ChatViewDataSourceManager sharedManager].publicChatArray;
NSInteger selfCount = self.publicChatArray.count;
NSInteger insertCount = arr.count - selfCount;
insertCount = insertCount > 10 ? 10 : insertCount;//判断未展示的消息数据是否大于10条
//加载10条数据
for (NSInteger i = arr.count - selfCount; i > arr.count - selfCount - insertCount; i--) {
[self.publicChatArray insertObject:arr[i] atIndex:0];
}
// NSLog(@"刷新了%d条数据,总条数%d, 目前条数%d", insertCount, arr.count, self.publicChatArray.count);
[self.publicTableView reloadData];
[self.publicTableView.mj_header endRefreshing];
}else{
// NSLog(@"没有更多数据了");
[self.publicTableView.mj_header endRefreshing];
}
}
避免tableView显示过多cell机制
//当前cell数量大于60时,加载最新20条,下拉刷新从单例数组中取
if (self.publicChatArray.count > 60) {
NSRange range =NSMakeRange(0, self.publicChatArray.count - 20);
[self.publicChatArray removeObjectsInRange:range];
// NSLog(@"count大于60,返回最新20条,目前消息条数%lu", self.publicChatArray.count);
}
总结
1.数据量过大时,延迟1S展示,通过数组打包交给ChatView渲染
2.舍弃机制,避免加载过多的cell,毕竟一个屏幕直播占一块,聊天占一块,没必要一次性加载100条,够两个屏幕的宽度就可以,然后通过下拉刷新去取数据就可以
tableView的其他坑
1.数据预处理
2.cell视图渲染
3.行高处理
4.异步获取聊天图片刷新