Objective-C映客房间消息策略分析与实现
2016-06-23 16:40
477 查看
最近直播这么火,今天分析一下映客的房间消息模块。
映客的房间消息策略大体上是这样的:
• 消息积累到一定量之后,便把之前的消息丢弃掉。
• 消息的显示是有消息则自动滚动到底部,如果用户滑动消息,则暂时停止滚动,5秒内不作操作则继续自动滚动。
• 消息在最底部的时候向下滑动并不会暂停自动滚动。
• 每一次滑动都会使计时器重置。
• 一段时间内如果有大量滚动到最底的消息,只处理一次。
• 房间消息刷新速度与消息频率相关
主要就分为消息丢弃和消息滚动两大点,下面来一一将讲述。
如果大于一定量的话则从数组中删除,视为消息发生重大变化并发布通知,刷UI。如:
在展示视图中我们接收到MessageReconstruct和MessageAppend两个通知,前者为需要重新获取DataSource并刷新tableView。后者则直接插入一行即可。
MessageReconstruct:
MessageAppend:
向上滑动时,来新消息暂时不自动滚屏,5秒内不操作自动滚屏
每一次滑动都会使计时器重置
一段时间内如果有大量滚动到最低的消息,只处理一次
消息在最底部的时候向下滑动并不会暂停自动滚动
先来定义两个滚动标记的bool值来标记是否自动滚动和一个定时器timer:
有消息滑动到底部:
在UIScrollViewDelegate控制滚动:
消息在最底部的时候向下滑动并不会暂停自动滚动:
保存下来_messageRate,可以看出消息频率每一秒钟更新一次,这样就可以根据消息的频率来动态制定消息显示、刷新和丢弃策略。
好了,大体就是这样,不管是IM还是直播房间消息,看似简单,其实还是有很多坑的,欢迎大家讨论交流。
映客的房间消息策略大体上是这样的:
• 消息积累到一定量之后,便把之前的消息丢弃掉。
• 消息的显示是有消息则自动滚动到底部,如果用户滑动消息,则暂时停止滚动,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还是直播房间消息,看似简单,其实还是有很多坑的,欢迎大家讨论交流。
相关文章推荐
- YY、映客、陌陌、KK、斗鱼五大直播阵营即将形成?
- 映客如此之火,殊不知已经有仿映客手机直播全新上市了!
- 仿照映客的直播界面的刷礼物效果
- 类似映客的直播app系统软件如何开发?
- 定制开发映客、花椒直播app微信直播
- 定制开发映客、花椒直播app 微信直播
- RTMPC直播连麦SDK助力APP成为下一个映客
- sketch 映客Android 设计
- android快速仿花椒,映客直播上下滑动切换直播间
- 小试牛刀-如何用数据洞察一场直播
- 仿映客直播礼物特效制作流程
- 映客在刀尖跳舞
- 仿映客刷礼物效果 代码优化
- Android开发仿映客送礼物效果
- enumerateObjectsUsingBlock,for in,for的区别和性能测试
- Effective Objective-C 2.0 第13条:理解“类对象”的用意
- 将前台的String转给后台,解析为list<Object>