123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- //
- // NIMSessionMsgDatasource.m
- // NIMKit
- //
- // Created by chris.
- // Copyright (c) 2015年 NetEase. All rights reserved.
- //
- #import "NIMSessionMsgDatasource.h"
- #import "UITableView+NIMScrollToBottom.h"
- #import "NIMMessageModel.h"
- #import "NIMTimestampModel.h"
- #import "NIMGlobalMacro.h"
- #import "NIMKit.h"
- @interface NIMSessionMsgDatasource()
- @property (nonatomic,strong) id<NIMKitMessageProvider> dataProvider;
- @property (nonatomic,strong) NSMutableDictionary *msgIdDict;
- @end
- @implementation NIMSessionMsgDatasource
- {
- NIMSession *_currentSession;
- dispatch_queue_t _messageQueue;
- }
- - (instancetype)initWithSession:(NIMSession*)session
- config:(id<NIMSessionConfig>)sessionConfig
- {
- if (self = [self init]) {
- _currentSession = session;
- _sessionConfig = sessionConfig;
- id<NIMKitMessageProvider> dataProvider = [_sessionConfig respondsToSelector:@selector(messageDataProvider)] ? [_sessionConfig messageDataProvider] : nil;
-
- NSInteger limit = [NIMKit sharedKit].config.messageLimit;
- NSTimeInterval showTimestampInterval = [NIMKit sharedKit].config.messageInterval;
-
- _dataProvider = dataProvider;
- _messageLimit = limit;
- _showTimeInterval = showTimestampInterval;
- _items = [NSMutableArray array];
- _msgIdDict = [NSMutableDictionary dictionary];
- }
- return self;
- }
- - (void)resetMessages:(void(^)(NSError *error)) handler
- {
- self.items = [NSMutableArray array];
- self.msgIdDict = [NSMutableDictionary dictionary];
- if ([self.dataProvider respondsToSelector:@selector(pullDown:handler:)])
- {
- __weak typeof(self) wself = self;
- [self.dataProvider pullDown:nil handler:^(NSError *error, NSArray<NIMMessage *> *messages) {
- NIMKit_Dispatch_Async_Main(^{
- [wself appendMessageModels:[self modelsWithMessages:messages]];
- if (handler) {
- handler(error);
- }
- });
- }];
- }
- else
- {
- NSArray<NIMMessage *> *messages = [[[NIMSDK sharedSDK] conversationManager] messagesInSession:_currentSession
- message:nil
- limit:_messageLimit];
- [self appendMessageModels:[self modelsWithMessages:messages]];
- if (handler) {
- handler(nil);
- }
- }
- }
- /**
- * 从头插入消息
- *
- * @param messages 消息
- *
- * @return 插入后table要滑动到的位置
- */
- - (NSInteger)insertMessages:(NSArray *)messages{
- NSInteger count = self.items.count;
- for (NIMMessage *message in messages.reverseObjectEnumerator.allObjects) {
- [self insertMessage:message];
- }
- NSInteger currentIndex = self.items.count - 1;
- return currentIndex - count;
- }
- /**
- * 从后插入消息
- *
- * @param models 消息集合
- *
- * @return 插入的消息的index
- */
- - (NSArray *)appendMessageModels:(NSArray *)models{
- if (!models.count) {
- return @[];
- }
- NSMutableArray *append = [[NSMutableArray alloc] init];
- for (NIMMessageModel *model in models) {
- if ([self modelIsExist:model]) {
- continue;
- }
- NSArray *result = [self insertMessageModel:model index:self.items.count];
- [append addObjectsFromArray:result];
- }
- return append;
- }
- /**
- * 从中间插入消息
- *
- * @param models 消息集合
- *
- * @return 插入消息的index
- */
- - (NSArray *)insertMessageModels:(NSArray *)models{
- if (!models.count) {
- return @[];
- }
- NSMutableArray *insert = [[NSMutableArray alloc] init];
- //由于找到插入位置后会直接插入,所以这里按时间戳大小先排个序,避免造成先插了时间大的,再插了时间小的,导致之前时间大的消息的位置还需要后移的情况.
- NSArray *sortModels = [models sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
- NIMMessageModel *first = obj1;
- NIMMessageModel *second = obj2;
- return first.messageTime < second.messageTime ? NSOrderedAscending : NSOrderedDescending;
- }];
- for (NIMMessageModel *model in sortModels) {
- if ([self modelIsExist:model]) {
- continue;
- }
- NSInteger i = [self findInsertPosistion:model];
- NSArray *result = [self insertMessageModel:model index:i];
- [insert addObjectsFromArray:result];
- }
- return insert;
- }
- - (NSInteger)indexAtModelArray:(NIMMessageModel *)model
- {
- __block NSInteger index = -1;
- if (![_msgIdDict objectForKey:model.message.messageId]) {
- return index;
- }
- [self.items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- if ([obj isKindOfClass:[NIMMessageModel class]]) {
- if ([model isEqual:obj]) {
- index = idx;
- *stop = YES;
- }
- }
- }];
- return index;
- }
- #pragma mark - msg
- - (BOOL)modelIsExist:(NIMMessageModel *)model
- {
- return [_msgIdDict objectForKey:model.message.messageId] != nil;
- }
- - (void)loadHistoryMessagesWithComplete:(void(^)(NSInteger index, NSArray *messages , NSError *error))handler
- {
- __block NIMMessageModel *currentOldestMsg = nil;
- [self.items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- if ([obj isKindOfClass:[NIMMessageModel class]]) {
- currentOldestMsg = (NIMMessageModel*)obj;
- *stop = YES;
- }
- }];
- NSInteger index = 0;
- if ([self.dataProvider respondsToSelector:@selector(pullDown:handler:)])
- {
- __weak typeof(self) wself = self;
- [self.dataProvider pullDown:currentOldestMsg.message handler:^(NSError *error, NSArray *messages) {
- NIMKit_Dispatch_Async_Main(^{
- NSInteger index = [wself insertMessages:messages];
- if (handler) {
- handler(index,messages,error);
- }
- });
- }];
- return;
- }
- else
- {
- NSArray *messages = [[[NIMSDK sharedSDK] conversationManager] messagesInSession:_currentSession
- message:currentOldestMsg.message
- limit:self.messageLimit];
- index = [self insertMessages:messages];
- if (handler) {
- NIMKit_Dispatch_Async_Main(^{
- handler(index,messages,nil);
- });
- }
- }
- }
- - (void)loadPullUpMessagesWithComplete:(void (^)(NSInteger, NSArray *, NSError *))handler {
- __block NIMMessageModel *currentNewestMsg = self.items.lastObject;
- __block NSInteger index = 0;
- NIMMessageSearchOption *option = [NIMMessageSearchOption new];
- option.startTime = currentNewestMsg.messageTime - 0.1;
- option.limit = [NIMKit sharedKit].config.messageLimit;
- option.allMessageTypes = YES;
- option.order = NIMMessageSearchOrderAsc;
- __weak typeof(self) wself = self;
- [[NIMSDK sharedSDK].conversationManager searchMessages:_currentSession
- option:option
- result:^(NSError * _Nullable error, NSArray<NIMMessage *> * _Nullable messages) {
- index = [wself appendMessageModels:[self modelsWithMessages:messages]].count;
- if (handler) {
- NIMKit_Dispatch_Async_Main(^{
- handler(index,messages,nil);
- });
- }
- }];
- }
- - (NSArray*)deleteMessageModel:(NIMMessageModel *)msgModel
- {
- NSMutableArray *dels = [NSMutableArray array];
- NSInteger delTimeIndex = -1;
- NSInteger delMsgIndex = [self.items indexOfObject:msgModel];
- if (delMsgIndex > 0) {
- BOOL delMsgIsSingle = (delMsgIndex == self.items.count-1 || [self.items[delMsgIndex+1] isKindOfClass:[NIMTimestampModel class]]);
- if ([self.items[delMsgIndex-1] isKindOfClass:[NIMTimestampModel class]] && delMsgIsSingle) {
- delTimeIndex = delMsgIndex-1;
- [self.items removeObjectAtIndex:delTimeIndex];
- [dels addObject:@(delTimeIndex)];
- }
- }
- if (delMsgIndex > -1) {
- [self.items removeObject:msgModel];
- [_msgIdDict removeObjectForKey:msgModel.message.messageId];
- [dels addObject:@(delMsgIndex)];
- }
- return dels;
- }
- - (NSArray<NSIndexPath *> *)deleteModels:(NSRange)range
- {
- NSArray *models = [self.items subarrayWithRange:range];
- NSMutableArray *dels = [NSMutableArray array];
- NSMutableArray *all = [NSMutableArray arrayWithArray:self.items];
- for (NIMMessageModel *model in models) {
- if ([model isKindOfClass:[NIMTimestampModel class]]) {
- continue;
- }
- NSInteger delTimeIndex = -1;
- NSInteger delMsgIndex = [all indexOfObject:model];
- if (delMsgIndex > 0) {
- BOOL delMsgIsSingle = (delMsgIndex == all.count-1 || [all[delMsgIndex+1] isKindOfClass:[NIMTimestampModel class]]);
- if ([all[delMsgIndex-1] isKindOfClass:[NIMTimestampModel class]] && delMsgIsSingle) {
- delTimeIndex = delMsgIndex-1;
- [self.items removeObjectAtIndex:delTimeIndex];
- NSIndexPath *indexpath = [NSIndexPath indexPathForRow:delTimeIndex inSection:0];
- [dels addObject:indexpath];
- }
- }
- if (delMsgIndex > -1) {
- [self.items removeObject:model];
- [_msgIdDict removeObjectForKey:model.message.messageId];
- NSIndexPath *indexpath = [NSIndexPath indexPathForRow:delMsgIndex inSection:0];
- [dels addObject:indexpath];
- }
- }
- return dels;
- }
- - (void)cleanCache
- {
- for (id item in self.items)
- {
- if ([item isKindOfClass:[NIMMessageModel class]])
- {
- NIMMessageModel *model = (NIMMessageModel *)item;
- [model cleanCache];
- }
- }
- }
- #pragma mark - private methods
- - (void)insertMessage:(NIMMessage *)message{
- NIMMessageModel *model = [[NIMMessageModel alloc] initWithMessage:message];
- if ([self modelIsExist:model]) {
- return;
- }
- NSTimeInterval firstTimeInterval = [self firstTimeInterval];
- if (firstTimeInterval && firstTimeInterval - model.messageTime < self.showTimeInterval) {
- //此时至少有一条消息和时间戳(如果有的话)
- //干掉时间戳(如果有的话)
- if ([self.items.firstObject isKindOfClass:[NIMTimestampModel class]]) {
- [self.items removeObjectAtIndex:0];
- }
- }
- [self.items insertObject:model atIndex:0];
- if (![self.dataProvider respondsToSelector:@selector(needTimetag)] || self.dataProvider.needTimetag) {
- //这种情况下必须要插入时间戳
- NIMTimestampModel *timeModel = [[NIMTimestampModel alloc] init];
- timeModel.messageTime = model.messageTime;
- [self.items insertObject:timeModel atIndex:0];
- }
- [self.msgIdDict setObject:model forKey:model.message.messageId];
- }
- - (NSArray *)insertMessageModel:(NIMMessageModel *)model index:(NSInteger)index{
- NSMutableArray *inserts = [[NSMutableArray alloc] init];
- if (![self.dataProvider respondsToSelector:@selector(needTimetag)] || self.dataProvider.needTimetag)
- {
- if ([self shouldInsertTimestamp:model]) {
- NIMTimestampModel *timeModel = [[NIMTimestampModel alloc] init];
- timeModel.messageTime = model.messageTime;
- [self.items insertObject:timeModel atIndex:index];
- [inserts addObject:@(index)];
- index++;
- }
- }
- [self.items insertObject:model atIndex:index];
- [self.msgIdDict setObject:model forKey:model.message.messageId];
- [inserts addObject:@(index)];
- return inserts;
- }
- - (void)subHeadMessages:(NSInteger)count
- {
- NSInteger catch = 0;
- NSArray *modelArray = [NSArray arrayWithArray:self.items];
- for (NIMMessageModel *model in modelArray) {
- if ([model isKindOfClass:[NIMMessageModel class]]) {
- catch++;
- [self deleteMessageModel:model];
- }
- if (catch == count) {
- break;
- }
- }
- }
- - (NSArray<NIMMessageModel *> *)modelsWithMessages:(NSArray<NIMMessage *> *)messages
- {
- NSMutableArray *array = [[NSMutableArray alloc] init];
- for (NIMMessage *message in messages) {
- NIMMessageModel *model = [[NIMMessageModel alloc] initWithMessage:message];
- [array addObject:model];
- }
- return array;
- }
- - (NSInteger)findInsertPosistion:(NIMMessageModel *)model
- {
- return [self findInsertPosistion:self.items model:model];
- }
- - (NSInteger)findInsertPosistion:(NSArray *)array model:(NIMMessageModel *)model
- {
- if (array.count == 0) {
- //即初始什么消息都没的情况下,调用了插入消息,放在第一个就好了。
- return 0;
- }
- if (array.count == 1) {
- //递归出口
- NIMMessageModel *obj = array.firstObject;
- NSInteger index = [self.items indexOfObject:obj];
- return obj.messageTime > model.messageTime? index : index+1;
- }
- NSInteger sep = (array.count+1) / 2;
- NIMMessageModel *center = array[sep];
- NSTimeInterval timestamp = [center messageTime];
- NSArray *half;
- if (timestamp <= [model messageTime]) {
- half = [array subarrayWithRange:NSMakeRange(sep, array.count - sep)];
- }else{
- half = [array subarrayWithRange:NSMakeRange(0, sep)];
- }
- return [self findInsertPosistion:half model:model];
- }
- - (BOOL)shouldInsertTimestamp:(NIMMessageModel *)model
- {
- NSTimeInterval lastTimeInterval = [self lastTimeInterval];
- return model.messageTime - lastTimeInterval > self.showTimeInterval;
- }
- - (NSTimeInterval)firstTimeInterval
- {
- if (!self.items.count) {
- return 0;
- }
- NIMMessageModel *model;
- if (![self.dataProvider respondsToSelector:@selector(needTimetag)] || self.dataProvider.needTimetag) {
- model = self.items[1];
- }else
- {
- model = self.items[0];
- }
- return model.messageTime;
- }
- - (NSTimeInterval)lastTimeInterval
- {
- NIMMessageModel *model = self.items.lastObject;
- return model.messageTime;
- }
- @end
|