NIMSessionMsgDatasource.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. //
  2. // NIMSessionMsgDatasource.m
  3. // NIMKit
  4. //
  5. // Created by chris.
  6. // Copyright (c) 2015年 NetEase. All rights reserved.
  7. //
  8. #import "NIMSessionMsgDatasource.h"
  9. #import "UITableView+NIMScrollToBottom.h"
  10. #import "NIMMessageModel.h"
  11. #import "NIMTimestampModel.h"
  12. #import "NIMGlobalMacro.h"
  13. #import "NIMKit.h"
  14. @interface NIMSessionMsgDatasource()
  15. @property (nonatomic,strong) id<NIMKitMessageProvider> dataProvider;
  16. @property (nonatomic,strong) NSMutableDictionary *msgIdDict;
  17. @end
  18. @implementation NIMSessionMsgDatasource
  19. {
  20. NIMSession *_currentSession;
  21. dispatch_queue_t _messageQueue;
  22. }
  23. - (instancetype)initWithSession:(NIMSession*)session
  24. config:(id<NIMSessionConfig>)sessionConfig
  25. {
  26. if (self = [self init]) {
  27. _currentSession = session;
  28. _sessionConfig = sessionConfig;
  29. id<NIMKitMessageProvider> dataProvider = [_sessionConfig respondsToSelector:@selector(messageDataProvider)] ? [_sessionConfig messageDataProvider] : nil;
  30. NSInteger limit = [NIMKit sharedKit].config.messageLimit;
  31. NSTimeInterval showTimestampInterval = [NIMKit sharedKit].config.messageInterval;
  32. _dataProvider = dataProvider;
  33. _messageLimit = limit;
  34. _showTimeInterval = showTimestampInterval;
  35. _items = [NSMutableArray array];
  36. _msgIdDict = [NSMutableDictionary dictionary];
  37. }
  38. return self;
  39. }
  40. - (void)resetMessages:(void(^)(NSError *error)) handler
  41. {
  42. self.items = [NSMutableArray array];
  43. self.msgIdDict = [NSMutableDictionary dictionary];
  44. if ([self.dataProvider respondsToSelector:@selector(pullDown:handler:)])
  45. {
  46. __weak typeof(self) wself = self;
  47. [self.dataProvider pullDown:nil handler:^(NSError *error, NSArray<NIMMessage *> *messages) {
  48. NIMKit_Dispatch_Async_Main(^{
  49. [wself appendMessageModels:[self modelsWithMessages:messages]];
  50. if (handler) {
  51. handler(error);
  52. }
  53. });
  54. }];
  55. }
  56. else
  57. {
  58. NSArray<NIMMessage *> *messages = [[[NIMSDK sharedSDK] conversationManager] messagesInSession:_currentSession
  59. message:nil
  60. limit:_messageLimit];
  61. [self appendMessageModels:[self modelsWithMessages:messages]];
  62. if (handler) {
  63. handler(nil);
  64. }
  65. }
  66. }
  67. /**
  68. * 从头插入消息
  69. *
  70. * @param messages 消息
  71. *
  72. * @return 插入后table要滑动到的位置
  73. */
  74. - (NSInteger)insertMessages:(NSArray *)messages{
  75. NSInteger count = self.items.count;
  76. for (NIMMessage *message in messages.reverseObjectEnumerator.allObjects) {
  77. [self insertMessage:message];
  78. }
  79. NSInteger currentIndex = self.items.count - 1;
  80. return currentIndex - count;
  81. }
  82. /**
  83. * 从后插入消息
  84. *
  85. * @param models 消息集合
  86. *
  87. * @return 插入的消息的index
  88. */
  89. - (NSArray *)appendMessageModels:(NSArray *)models{
  90. if (!models.count) {
  91. return @[];
  92. }
  93. NSMutableArray *append = [[NSMutableArray alloc] init];
  94. for (NIMMessageModel *model in models) {
  95. if ([self modelIsExist:model]) {
  96. continue;
  97. }
  98. NSArray *result = [self insertMessageModel:model index:self.items.count];
  99. [append addObjectsFromArray:result];
  100. }
  101. return append;
  102. }
  103. /**
  104. * 从中间插入消息
  105. *
  106. * @param models 消息集合
  107. *
  108. * @return 插入消息的index
  109. */
  110. - (NSArray *)insertMessageModels:(NSArray *)models{
  111. if (!models.count) {
  112. return @[];
  113. }
  114. NSMutableArray *insert = [[NSMutableArray alloc] init];
  115. //由于找到插入位置后会直接插入,所以这里按时间戳大小先排个序,避免造成先插了时间大的,再插了时间小的,导致之前时间大的消息的位置还需要后移的情况.
  116. NSArray *sortModels = [models sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
  117. NIMMessageModel *first = obj1;
  118. NIMMessageModel *second = obj2;
  119. return first.messageTime < second.messageTime ? NSOrderedAscending : NSOrderedDescending;
  120. }];
  121. for (NIMMessageModel *model in sortModels) {
  122. if ([self modelIsExist:model]) {
  123. continue;
  124. }
  125. NSInteger i = [self findInsertPosistion:model];
  126. NSArray *result = [self insertMessageModel:model index:i];
  127. [insert addObjectsFromArray:result];
  128. }
  129. return insert;
  130. }
  131. - (NSInteger)indexAtModelArray:(NIMMessageModel *)model
  132. {
  133. __block NSInteger index = -1;
  134. if (![_msgIdDict objectForKey:model.message.messageId]) {
  135. return index;
  136. }
  137. [self.items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  138. if ([obj isKindOfClass:[NIMMessageModel class]]) {
  139. if ([model isEqual:obj]) {
  140. index = idx;
  141. *stop = YES;
  142. }
  143. }
  144. }];
  145. return index;
  146. }
  147. #pragma mark - msg
  148. - (BOOL)modelIsExist:(NIMMessageModel *)model
  149. {
  150. return [_msgIdDict objectForKey:model.message.messageId] != nil;
  151. }
  152. - (void)loadHistoryMessagesWithComplete:(void(^)(NSInteger index, NSArray *messages , NSError *error))handler
  153. {
  154. __block NIMMessageModel *currentOldestMsg = nil;
  155. [self.items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  156. if ([obj isKindOfClass:[NIMMessageModel class]]) {
  157. currentOldestMsg = (NIMMessageModel*)obj;
  158. *stop = YES;
  159. }
  160. }];
  161. NSInteger index = 0;
  162. if ([self.dataProvider respondsToSelector:@selector(pullDown:handler:)])
  163. {
  164. __weak typeof(self) wself = self;
  165. [self.dataProvider pullDown:currentOldestMsg.message handler:^(NSError *error, NSArray *messages) {
  166. NIMKit_Dispatch_Async_Main(^{
  167. NSInteger index = [wself insertMessages:messages];
  168. if (handler) {
  169. handler(index,messages,error);
  170. }
  171. });
  172. }];
  173. return;
  174. }
  175. else
  176. {
  177. NSArray *messages = [[[NIMSDK sharedSDK] conversationManager] messagesInSession:_currentSession
  178. message:currentOldestMsg.message
  179. limit:self.messageLimit];
  180. index = [self insertMessages:messages];
  181. if (handler) {
  182. NIMKit_Dispatch_Async_Main(^{
  183. handler(index,messages,nil);
  184. });
  185. }
  186. }
  187. }
  188. - (void)loadPullUpMessagesWithComplete:(void (^)(NSInteger, NSArray *, NSError *))handler {
  189. __block NIMMessageModel *currentNewestMsg = self.items.lastObject;
  190. __block NSInteger index = 0;
  191. NIMMessageSearchOption *option = [NIMMessageSearchOption new];
  192. option.startTime = currentNewestMsg.messageTime - 0.1;
  193. option.limit = [NIMKit sharedKit].config.messageLimit;
  194. option.allMessageTypes = YES;
  195. option.order = NIMMessageSearchOrderAsc;
  196. __weak typeof(self) wself = self;
  197. [[NIMSDK sharedSDK].conversationManager searchMessages:_currentSession
  198. option:option
  199. result:^(NSError * _Nullable error, NSArray<NIMMessage *> * _Nullable messages) {
  200. index = [wself appendMessageModels:[self modelsWithMessages:messages]].count;
  201. if (handler) {
  202. NIMKit_Dispatch_Async_Main(^{
  203. handler(index,messages,nil);
  204. });
  205. }
  206. }];
  207. }
  208. - (NSArray*)deleteMessageModel:(NIMMessageModel *)msgModel
  209. {
  210. NSMutableArray *dels = [NSMutableArray array];
  211. NSInteger delTimeIndex = -1;
  212. NSInteger delMsgIndex = [self.items indexOfObject:msgModel];
  213. if (delMsgIndex > 0) {
  214. BOOL delMsgIsSingle = (delMsgIndex == self.items.count-1 || [self.items[delMsgIndex+1] isKindOfClass:[NIMTimestampModel class]]);
  215. if ([self.items[delMsgIndex-1] isKindOfClass:[NIMTimestampModel class]] && delMsgIsSingle) {
  216. delTimeIndex = delMsgIndex-1;
  217. [self.items removeObjectAtIndex:delTimeIndex];
  218. [dels addObject:@(delTimeIndex)];
  219. }
  220. }
  221. if (delMsgIndex > -1) {
  222. [self.items removeObject:msgModel];
  223. [_msgIdDict removeObjectForKey:msgModel.message.messageId];
  224. [dels addObject:@(delMsgIndex)];
  225. }
  226. return dels;
  227. }
  228. - (NSArray<NSIndexPath *> *)deleteModels:(NSRange)range
  229. {
  230. NSArray *models = [self.items subarrayWithRange:range];
  231. NSMutableArray *dels = [NSMutableArray array];
  232. NSMutableArray *all = [NSMutableArray arrayWithArray:self.items];
  233. for (NIMMessageModel *model in models) {
  234. if ([model isKindOfClass:[NIMTimestampModel class]]) {
  235. continue;
  236. }
  237. NSInteger delTimeIndex = -1;
  238. NSInteger delMsgIndex = [all indexOfObject:model];
  239. if (delMsgIndex > 0) {
  240. BOOL delMsgIsSingle = (delMsgIndex == all.count-1 || [all[delMsgIndex+1] isKindOfClass:[NIMTimestampModel class]]);
  241. if ([all[delMsgIndex-1] isKindOfClass:[NIMTimestampModel class]] && delMsgIsSingle) {
  242. delTimeIndex = delMsgIndex-1;
  243. [self.items removeObjectAtIndex:delTimeIndex];
  244. NSIndexPath *indexpath = [NSIndexPath indexPathForRow:delTimeIndex inSection:0];
  245. [dels addObject:indexpath];
  246. }
  247. }
  248. if (delMsgIndex > -1) {
  249. [self.items removeObject:model];
  250. [_msgIdDict removeObjectForKey:model.message.messageId];
  251. NSIndexPath *indexpath = [NSIndexPath indexPathForRow:delMsgIndex inSection:0];
  252. [dels addObject:indexpath];
  253. }
  254. }
  255. return dels;
  256. }
  257. - (void)cleanCache
  258. {
  259. for (id item in self.items)
  260. {
  261. if ([item isKindOfClass:[NIMMessageModel class]])
  262. {
  263. NIMMessageModel *model = (NIMMessageModel *)item;
  264. [model cleanCache];
  265. }
  266. }
  267. }
  268. #pragma mark - private methods
  269. - (void)insertMessage:(NIMMessage *)message{
  270. NIMMessageModel *model = [[NIMMessageModel alloc] initWithMessage:message];
  271. if ([self modelIsExist:model]) {
  272. return;
  273. }
  274. NSTimeInterval firstTimeInterval = [self firstTimeInterval];
  275. if (firstTimeInterval && firstTimeInterval - model.messageTime < self.showTimeInterval) {
  276. //此时至少有一条消息和时间戳(如果有的话)
  277. //干掉时间戳(如果有的话)
  278. if ([self.items.firstObject isKindOfClass:[NIMTimestampModel class]]) {
  279. [self.items removeObjectAtIndex:0];
  280. }
  281. }
  282. [self.items insertObject:model atIndex:0];
  283. if (![self.dataProvider respondsToSelector:@selector(needTimetag)] || self.dataProvider.needTimetag) {
  284. //这种情况下必须要插入时间戳
  285. NIMTimestampModel *timeModel = [[NIMTimestampModel alloc] init];
  286. timeModel.messageTime = model.messageTime;
  287. [self.items insertObject:timeModel atIndex:0];
  288. }
  289. [self.msgIdDict setObject:model forKey:model.message.messageId];
  290. }
  291. - (NSArray *)insertMessageModel:(NIMMessageModel *)model index:(NSInteger)index{
  292. NSMutableArray *inserts = [[NSMutableArray alloc] init];
  293. if (![self.dataProvider respondsToSelector:@selector(needTimetag)] || self.dataProvider.needTimetag)
  294. {
  295. if ([self shouldInsertTimestamp:model]) {
  296. NIMTimestampModel *timeModel = [[NIMTimestampModel alloc] init];
  297. timeModel.messageTime = model.messageTime;
  298. [self.items insertObject:timeModel atIndex:index];
  299. [inserts addObject:@(index)];
  300. index++;
  301. }
  302. }
  303. [self.items insertObject:model atIndex:index];
  304. [self.msgIdDict setObject:model forKey:model.message.messageId];
  305. [inserts addObject:@(index)];
  306. return inserts;
  307. }
  308. - (void)subHeadMessages:(NSInteger)count
  309. {
  310. NSInteger catch = 0;
  311. NSArray *modelArray = [NSArray arrayWithArray:self.items];
  312. for (NIMMessageModel *model in modelArray) {
  313. if ([model isKindOfClass:[NIMMessageModel class]]) {
  314. catch++;
  315. [self deleteMessageModel:model];
  316. }
  317. if (catch == count) {
  318. break;
  319. }
  320. }
  321. }
  322. - (NSArray<NIMMessageModel *> *)modelsWithMessages:(NSArray<NIMMessage *> *)messages
  323. {
  324. NSMutableArray *array = [[NSMutableArray alloc] init];
  325. for (NIMMessage *message in messages) {
  326. NIMMessageModel *model = [[NIMMessageModel alloc] initWithMessage:message];
  327. [array addObject:model];
  328. }
  329. return array;
  330. }
  331. - (NSInteger)findInsertPosistion:(NIMMessageModel *)model
  332. {
  333. return [self findInsertPosistion:self.items model:model];
  334. }
  335. - (NSInteger)findInsertPosistion:(NSArray *)array model:(NIMMessageModel *)model
  336. {
  337. if (array.count == 0) {
  338. //即初始什么消息都没的情况下,调用了插入消息,放在第一个就好了。
  339. return 0;
  340. }
  341. if (array.count == 1) {
  342. //递归出口
  343. NIMMessageModel *obj = array.firstObject;
  344. NSInteger index = [self.items indexOfObject:obj];
  345. return obj.messageTime > model.messageTime? index : index+1;
  346. }
  347. NSInteger sep = (array.count+1) / 2;
  348. NIMMessageModel *center = array[sep];
  349. NSTimeInterval timestamp = [center messageTime];
  350. NSArray *half;
  351. if (timestamp <= [model messageTime]) {
  352. half = [array subarrayWithRange:NSMakeRange(sep, array.count - sep)];
  353. }else{
  354. half = [array subarrayWithRange:NSMakeRange(0, sep)];
  355. }
  356. return [self findInsertPosistion:half model:model];
  357. }
  358. - (BOOL)shouldInsertTimestamp:(NIMMessageModel *)model
  359. {
  360. NSTimeInterval lastTimeInterval = [self lastTimeInterval];
  361. return model.messageTime - lastTimeInterval > self.showTimeInterval;
  362. }
  363. - (NSTimeInterval)firstTimeInterval
  364. {
  365. if (!self.items.count) {
  366. return 0;
  367. }
  368. NIMMessageModel *model;
  369. if (![self.dataProvider respondsToSelector:@selector(needTimetag)] || self.dataProvider.needTimetag) {
  370. model = self.items[1];
  371. }else
  372. {
  373. model = self.items[0];
  374. }
  375. return model.messageTime;
  376. }
  377. - (NSTimeInterval)lastTimeInterval
  378. {
  379. NIMMessageModel *model = self.items.lastObject;
  380. return model.messageTime;
  381. }
  382. @end