您的位置:首页 > 移动开发 > Objective-C

Objective-C映客房间消息策略分析与实现

2016-06-23 16:40 477 查看
最近直播这么火,今天分析一下映客的房间消息模块。

映客的房间消息策略大体上是这样的:

• 消息积累到一定量之后,便把之前的消息丢弃掉。

• 消息的显示是有消息则自动滚动到底部,如果用户滑动消息,则暂时停止滚动,5秒内不作操作则继续自动滚动。

• 消息在最底部的时候向下滑动并不会暂停自动滚动。

• 每一次滑动都会使计时器重置。

• 一段时间内如果有大量滚动到最底的消息,只处理一次。

• 房间消息刷新速度与消息频率相关

主要就分为消息丢弃和消息滚动两大点,下面来一一将讲述。

1.消息丢弃

我们在往消息tableView的DataSource添加数据的时候检测数组的count,有消息来的话则插入数组,当count大于一定数量则移除之前的消息,需要注意的是红包消息不应丢弃:

[_dataArr insertObject:object atIndex:[_dataArr count]];


如果大于一定量的话则从数组中删除,视为消息发生重大变化并发布通知,刷UI。如:

BOOL afterCleaned = NO;
if(_dataArr.count > 250){
[_dataArr removeObjectsInRange:NSMakeRange(0, 200)];
afterCleaned = YES;
}
if(afterCleaned){
[[NSNotificationCenter defaultCenter]postNotificationName:@"MessageReconstruct" object:object];
}else{
[[NSNotificationCenter defaultCenter]postNotificationName:@"MessageAppend" object:object];
}


在展示视图中我们接收到MessageReconstruct和MessageAppend两个通知,前者为需要重新获取DataSource并刷新tableView。后者则直接插入一行即可。

MessageReconstruct:

-(void)notificationReconstructMessage:(NSNotification*)notification{
// 消息发生较大变化时,重新加载
[self reloadDatas];
// 重新加载,并滚动到最底
[self scrollToBottomMessage];
}


MessageAppend:

-(void)notificationAppendMessage:(NSNotification*)notification{

// 新增消息,不重新加载所有消息(Cell)
NSInteger rowCount = [_tableView numberOfRowsInSection:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowCount inSection:0];
NSArray *indexPaths = [[NSArray alloc]initWithObjects:indexPath, nil];

// First , prepare the new data
[_data addObject:notification.object];

[_tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationBottom];

if(_autoMoveBottom){
[self scrollToBottomMessage];
}
}


2.消息滚动

消息滚动策略是:

向上滑动时,来新消息暂时不自动滚屏,5秒内不操作自动滚屏

每一次滑动都会使计时器重置

一段时间内如果有大量滚动到最低的消息,只处理一次

消息在最底部的时候向下滑动并不会暂停自动滚动

先来定义两个滚动标记的bool值来标记是否自动滚动和一个定时器timer:

// 新消息到来自动滚动到最底下,如果NO,则新增消息时,不自动滚动
@property (nonatomic, assign) BOOL autoMoveBottom;
@property (nonatomic, strong) NSTimer *timer;
// 有还未执行的ScrollToBottom
@property (nonatomic, assign) BOOL hasPendingScroll;


有消息滑动到底部:

//有消息滑动到底部
-(void)scrollToBottomMessage{
//向上滑动时,来新消息暂时不自动滚屏,5秒内不操作自动滚屏
// 一段时间内如果有大量滚动到最低的消息,只处理一次
if(_hasPendingScroll)
return;

_hasPendingScroll = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSInteger bottomRow = [_tableView numberOfRowsInSection:0];
if(bottomRow == 0){
_hasPendingScroll = NO;
return;
}

[_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:bottomRow - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
_hasPendingScroll = NO;
});
}


在UIScrollViewDelegate控制滚动:

#pragma mark UIScrollViewDelegate
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
//    _oldContentOffsetY = scrollView.contentOffset.y;
_autoMoveBottom = NO;
//5秒不操作有新消息自动滚屏
//先暂停计时
[_timer setFireDate:[NSDate distantFuture]];
//重置计时器
_timer = [NSTimer scheduledTimerWithTimeInterval:autoMoveBottom_time target:self selector:@selector(setAutoMoveBottomYes) userInfo:nil repeats:NO];
}


- (void)setAutoMoveBottomYes{
_autoMoveBottom = YES;
[_timer invalidate];
_timer = nil;
}


消息在最底部的时候向下滑动并不会暂停自动滚动:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{

if(scrollView.contentOffset.y > ((scrollView.contentSize.height - scrollView.frame.size.height))){
_autoMoveBottom = YES;
}
}


3.消息刷新

当有消息来的时候可以这样做:

_messageRate++;
if(!_willPerform){
_willPerform = YES;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self _updataMessageRate];
});
}
- (void)_updataMessageRate{
NSLog(@"消息频率:%@/s", @(_messageRate));
_messageRate = 0;
_willPerform = NO;
}


保存下来_messageRate,可以看出消息频率每一秒钟更新一次,这样就可以根据消息的频率来动态制定消息显示、刷新和丢弃策略。

好了,大体就是这样,不管是IM还是直播房间消息,看似简单,其实还是有很多坑的,欢迎大家讨论交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  直播消息 映客