最近会话


最近会话概念

最近会话用于表示会话列表页的数据模型。当用户发送,收取及删除消息时,都会同时去修改最近会话。

当收到或者一条消息时,会自动生成这个消息对应的最近会话。但值得注意的是最近会话和会话并不是一一对应的关系,删除最近会话并不会影响会话。

最近会话类与属性

最近会话在 SDK 中用 NIMRecentSession 表示

/**
 *  最近会话
 */
@interface NIMRecentSession : NSObject

/**
 *  当前会话
 */
@property (nullable,nonatomic,readonly,copy)   NIMSession  *session;

/**
 *  最后一条消息
 */
@property (nullable,nonatomic,readonly,strong)   NIMMessage  *lastMessage;

/**
 *  未读消息数,为保证线程安全,请在主线程中获取
 */
@property (nonatomic,readonly,assign)   NSInteger   unreadCount;

/**
 *  本地扩展
 */
@property (nullable,nonatomic,readonly,copy) NSDictionary *localExt;

@end

属性列表

参数 类型 说明
session NIMSession 表示的当前会话
lastMessage NIMMessage 当前会话的最后一条消息
unreadCount NSInteger 未读消息数,为保证线程安全,请在主线程中获取
localExt NSDictionary 最近会话的本地扩展,修改后,需要调用 NIMConversationManagerProtocolupdateRecentLocalExt:recentSession: 方法,才可以存储到本地

NIMConversationManagerProtocol.h 中的 NIMConversationManager 协议用于增删改查本地消息和最近会话, NIMConversationManagerDelegate 协议用于回调通知最近会话的变更,下面会针对具体接口详细论述。

原型

@protocol NIMConversationManager <NSObject>
/**
 *  获取所有最近会话
 *  @discussion 只能在主线程调用
 *  @return 最近会话列表
 */
- (nullable NSArray<NIMRecentSession *> *)allRecentSessions;
@end

为了保证线程安全,这个方法只能在主线程调用,并且由于最近会话在内部是以字典形式存储的,在取出时,会对其进行排序,在数据量过万的情况下会有一定的耗时。

示例

//  NIMSessionListViewController.m
- (void)viewDidLoad {
    ...
    NSArray *recentSessions = [NIMSDK sharedSDK].conversationManager.allRecentSessions;
    ...
}

NIMConversationManagerDelegate 提供了最近会话的三个回调通知上层:

分别为增加,修改,删除最近会话的回调:

@protocol NIMConversationManagerDelegate <NSObject>
/**
 *  增加最近会话的回调
 *
 *  @param recentSession    最近会话
 *  @param totalUnreadCount 目前总未读数
 *  @discussion 当新增一条消息,并且本地不存在该消息所属的会话时,会触发此回调。
 */
- (void)didAddRecentSession:(NIMRecentSession *)recentSession
           totalUnreadCount:(NSInteger)totalUnreadCount;

/**
 *  最近会话修改的回调
 *
 *  @param recentSession    最近会话
 *  @param totalUnreadCount 目前总未读数
 *  @discussion 触发条件包括: 1.当新增一条消息,并且本地存在该消息所属的会话。
 *                          2.所属会话的未读清零。
 *                          3.所属会话的最后一条消息的内容发送变化。(例如成功发送后,修正发送时间为服务器时间)
 *                          4.删除消息,并且删除的消息为当前会话的最后一条消息。
 */
- (void)didUpdateRecentSession:(NIMRecentSession *)recentSession
              totalUnreadCount:(NSInteger)totalUnreadCount;

/**
 *  删除最近会话的回调
 *
 *  @param recentSession    最近会话
 *  @param totalUnreadCount 目前总未读数
 */
- (void)didRemoveRecentSession:(NIMRecentSession *)recentSession
              totalUnreadCount:(NSInteger)totalUnreadCount;

@end

属性列表

参数 类型 说明
recentSession NIMRecentSession 产生变化的最近会话
totalUnreadCount NSInteger 目前总未读数

获取单个 NIMRecentSession 的未读数时,可以通过回调上来的 NIMRecentSessionunreadCount 属性直接获取。

开发者无法自己添加最近消息,最近消息会在发送或者收到消息的时候自动添加,并触发增加最近会话的回调。

可以通过 NIMConversationManager 获取消息的总未读数,注意为了保证线程安全,只能在主线程上调用读取此数据

@protocol NIMConversationManager <NSObject>
/**
 *  获取所有未读数
 *  @discussion 只能在主线程调用,包括忽略提醒的会话
 *  @return 未读数
 */
- (NSInteger)allUnreadCount;
@end

当 SDK 收到消息后,默认消息为未读消息,未读数累加 1 。因为 SDK 是和 UI 完全隔离的,SDK 无法自动感知何时消息已读,故需要上层开发者根据自己的 UI 逻辑,在恰当的时候,手动调用标记已读 接口来告诉 SDK ,从而 SDK 可以进行清除未读数,标记消息状态等之后的维护工作。 相应的最近会话(如果有的话)未读数会自动置 0 并且触发最近消息修改的回调。

原型

@protocol NIMConversationManager <NSObject>
/**
 *  设置一个会话里所有消息置为已读
 *
 *  @param session 需设置的会话
 *  @discussion 异步方法,消息会标记为设置的状态
 */
- (void)markAllMessagesReadInSession:(NIMSession *)session;
@end

示例

//  NIMSessionViewController.m
- (void)onRecvMessages:(NSArray *)messages
{
    ....
    //会话页直接监听收到消息后的回调,并由于当前页是在会话,直接认为已读
    if ([session isEqual:self.session])
    {
        //只有当消息所属会话时会话页表示的会话时,才标记已读
        [[NIMSDK sharedSDK].conversationManager markAllMessagesReadInSession:self.session];
    }
    ....
}

单条消息的删除


@protocol NIMConversationManager <NSObject>

/**
 *  删除某条消息
 *
 *  @param message 待删除的聊天消息
 */
- (void)deleteMessage:(NIMMessage *)message;

@end

调用此方法时,如果删除的是最后一条消息,消息所属的最近会话的 lastMessage 属性会自动变成上一条消息(没有则为空消息),同时触发最近消息修改的回调。

单个会话批量消息删除

@protocol NIMConversationManager <NSObject>
/**
 *  删除某个会话的所有消息
 *
 *  @param session 待删除会话
 *  @param option 删除消息选项
 */
- (void)deleteAllmessagesInSession:(NIMSession *)session
                            option:(nullable NIMDeleteMessagesOption *)option;
@end

NIMDeleteMessagesOption 参数列表

参数 类型 说明
removeSession BOOL 是否移除对应最近会话,批量删除消息时是否移除最近会话,默认为 NO,设置为 YES 时将同时删除最近会话信息
removeTable BOOL 是否删除消息表,默认情况下云信采用标记的方式进行消息删除,如果设置为 YES,将一并移除对应的消息表,进而减少消息表数量,加快 I/O
@protocol NIMConversationManager <NSObject>
/**
 *  删除某个最近会话
 *
 *  @param recentSession 待删除的最近会话
 *  @discussion 异步方法,删除最近会话,但保留会话内消息
 */
- (void)deleteRecentSession:(NIMRecentSession *)recentSession
@end

只会删除最近会话,但保留会话内消息。调用时,总未读消息数会减去当前会话的未读数。调用此方法触发最近消息删除的回调。

@protocol NIMConversationManager <NSObject>
/**
 *  删除所有会话消息
 *
 *  @param option 删除消息选项
 *  @discussion 调用这个接口只会触发allMessagesDeleted这个回调,其他针对单个recentSession的回调都不会被调用
 */
- (void)deleteAllMessages:(NIMDeleteMessagesOption *)option
@end

NIMDeleteMessagesOption 参数列表

属性列表

参数 类型 说明
removeSession BOOL 是否移除对应最近会话,批量删除消息时是否移除最近会话,默认为 NO,设置为 YES 时将同时删除最近会话信息
removeTable BOOL 是否删除消息表,默认情况下云信采用标记的方式进行消息删除,如果设置为 YES,将一并移除对应的消息表,进而减少消息表数量,加快 I/O
@protocol NIMConversationManager <NSObject>

/**
 *  删除服务器端最近会话
 *
 *  @param sessions   需要删除的会话列表,内部只能是NIMSession
 *  @param completion 完成的回调
 *  @discussion       调用这个接口成功后,当前会话之前的消息都不会漫游到其他端
 */
- (void)deleteRemoteSessions:(NSArray<NIMSession *> *)sessions
                  completion:(nullable NIMRemoveRemoteSessionBlock)completion;

@end

属性列表

参数 类型 说明
sessions NSArray * 需要删除的会话列表,内部只能是NIMSession
completion NIMRemoveRemoteSessionBlock 远端会话删除错误回调

部分类型消息支持不发送直接写入本地,目前支持的类型为: 1.文本类型 ( NIMMessageTypeText ) 2.提醒类型 ( NIMMessageTypeTip ) 3.自定义类型 ( NIMMessageTypeCustom )

原型

@protocol NIMConversationManager <NSObject>
/**
 *  写入消息
 *
 *  @param message 需要更新的消息
 *  @param session 需要更新的会话
 *  @param completion 完成后的回调
 *  @discussion 当保存消息成功之后,会收到 NIMChatManagerDelegate 中的 onRecvMessages: 回调。目前支持消息类型:NIMMessageTypeText,NIMMessageTypeTip,NIMMessageTypeCustom
 */
- (void)saveMessage:(NIMMessage *)message
         forSession:(NIMSession *)session
         completion:(nullable NIMUpdateMessageBlock)completion;
@end

属性列表

参数 类型 说明
message NIMMessage 需要写入的没有被发送的消息,支持类型见上文
session NIMSession 消息所在的会话
completion NIMUpdateMessageBlock 完成后的回调

方法为异步写入,无须开发者在上层单独开线程,直接在当前线程调用即可。

消息的部分属性支持在本地更新,目前可更新的字段为本地扩展字段 LocalExt 以及自定义消息的附件对象 messageObject

原型

@protocol NIMConversationManager <NSObject>
/**
 *  更新本地已存的消息记录
 *
 *  @param message 需要更新的消息
 *  @param session 需要更新的会话
 *  @param completion 完成后的回调
 *  @discussion 为了保证存储消息的完整性,提供给上层调用的消息更新接口只允许更新如下字段:所有消息的本地拓展字段(LocalExt)和自定义消息的消息对象(messageObject)
 */
- (void)updateMessage:(NIMMessage *)message
           forSession:(NIMSession *)session
           completion:(nullable NIMUpdateMessageBlock)completion;
@end

属性列表

参数 类型 说明
message NIMMessage 需要被更新的消息,支持的更新属性见上文
session NIMSession 消息所在的会话
completion NIMUpdateMessageBlock 完成后的回调

方法为异步写入,无须开发者在上层单独开线程,直接在当前线程调用即可。

@protocol NIMConversationManager <NSObject>
/**
 *  导入最近会话
 *
 *  @param importedRecentSession 待导入的会话集合
 *  @param completion 完成后的回调
 *  @discussion 当导入最近会话成功之后,不会收到 NIMChatManagerDelegate 中的 recentSession 变化的回调,请直接在 completion 中做处理。不允许插入已经存在的最近会话。
 */
- (void)importRecentSessions:(NSArray<NIMImportedRecentSession *> *)importedRecentSession
                  completion:(nullable NIMImportRecentSessionsBlock)completion;
@end

属性列表

参数 类型 说明
importedRecentSession NSArray * 待导入的会话集合
completion NIMImportRecentSessionsBlock 完成后的回调

方法为异步写入,无须开发者在上层单独开线程,直接在当前线程调用即可。

最近会话提供本地扩展能力,可以用来开发 @ 以及 置顶 等功能。

开发者可以通过 RecentSessionlocalExt 接口读取扩展。

并通过调用 NIMConversationManager 修改本地扩展信息

原型

@protocol NIMConversationManager <NSObject>
/**
 *  更新最近会话的本地扩展
 *
 *  @param ext           扩展信息
 *  @param recentSession 要更新的最近会话
 *  @discussion          此扩展不会漫游到其他端,上层需要保证 NSDictionary 可以转换为 JSON。
 */
- (void)updateRecentLocalExt:(nullable NSDictionary *)ext
               recentSession:(NIMRecentSession *)recentSession;

@end

属性列表

参数 类型 说明
ext NSDictionary 扩展信息,上层需要保证能将 NSDictionary 转换为 JSON
recentSession NIMRecentSession 要更新的最近会话

示例

// NTESSessionUtil.m
+ (void)addRecentSessionAtMark:(NIMSession *)session
{
    //为会话添加 有人@你 的的标记
    NIMRecentSession *recent = [[NIMSDK sharedSDK].conversationManager recentSessionBySession:session];
    if (recent)
    {
        NSDictionary *localExt = recent.localExt?:@{};
        NSMutableDictionary *dict = [localExt mutableCopy];
        [dict setObject:@(YES) forKey:NTESRecentSessionAtMark];
        [[NIMSDK sharedSDK].conversationManager updateRecentLocalExt:dict recentSession:recent];
    }
}