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

最近直播这么火,今天分析一下映客的房间消息模块。
映客的房间消息策略大体上是这样的:

  • • 消息积累到一定量之后,便把之前的消息丢弃掉。
  • • 消息的显示是有消息则自动滚动到底部,如果用户滑动消息,则暂时停止滚动,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还是直播房间消息,看似简单,其实还是有很多坑的,欢迎大家讨论交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值