聊天页面中,可以通过按时间间隔(如每 5 分钟、每小时、每天等)对聊天数据分组。
-
枚举:定义分组粒度类型
/// 聊天消息的分组粒度
enum ChatGroupInterval {
/// 每 5 分钟一组
case fiveMinutes
/// 每 30 分钟一组
case thirtyMinutes
/// 每小时一组
case hourly
/// 每天一组
case daily
/// 对应的时间间隔(秒)
var timeInterval: TimeInterval {
switch self {
case .fiveMinutes: return 5 * 60
case .thirtyMinutes: return 30 * 60
case .hourly: return 60 * 60
case .daily: return 24 * 60 * 60
}
}
}
-
分组方法:对 [ChatMessage] 按指定规则进行分组
1、分组逻辑:
每条消息的 create_time 会与当前组内最后一条消息的时间进行比较。如果两者的时间差超过指定的间隔(例如,10分钟),就开始一个新的分组。
2、每组的 groupDate:
每组的 groupDate 应该是该组内第一条消息的时间。
extension Array where Element == MessageModel {
/// 按时间间隔进行分组
func grouped(by interval: ChatGroupInterval) -> [(groupDate: Date, messages: [MessageModel])] {
var result: [(Date, [MessageModel])] = []
var currentGroup: [MessageModel] = []
var lastMessageDate: Date?
for message in self.sorted(by: { $0.create_time.toDate(region: .local)! < $1.create_time.toDate(region: .local)! }) {
// 获取消息的时间
guard let messageDateInRegion = message.create_time.toDate(region: .local) else { continue }
let messageDate = messageDateInRegion.date
// 判断当前消息与上条消息的时间差
if let lastDate = lastMessageDate {
let timeDifference = messageDate.timeIntervalSince(lastDate)
if timeDifference > interval.timeInterval {
// 时间差超过间隔,创建新分组
if !currentGroup.isEmpty {
result.append((currentGroup.first!.create_time.toDate(region: .local)!.date, currentGroup))
}
currentGroup = [message]
} else {
// 时间差未超过间隔,继续添加到当前分组
currentGroup.append(message)
}
} else {
// 这是第一条消息,直接加入
currentGroup.append(message)
}
// 更新 lastMessageDate 为当前消息时间
lastMessageDate = messageDate
}
// 将最后一个分组添加到结果
if !currentGroup.isEmpty {
result.append((currentGroup.first!.create_time.toDate(region: .local)!.date, currentGroup))
}
return result
}
}
extension Array where Element == (groupDate: Date, messages: [MessageModel]) {
/// 将新消息添加到现有分组中,并返回是否新建分组
/// - Parameters:
/// - message: 消息
/// - interval: 聊天消息的分组粒度
/// - Returns: 返回是否新建分组
mutating func addMessage(_ message: MessageModel, interval: ChatGroupInterval) -> Bool? {
guard let messageDateInRegion = message.create_time.toDate(region: .local) else { return nil }
let messageDate = messageDateInRegion.date // 将 DateInRegion 转换为 Date
PrintLog(message: messageDate)
// 如果当前有分组
if let lastGroupIndex = self.lastIndex(where: { messageDate.timeIntervalSince($0.groupDate) <= interval.timeInterval }) {
// 获取分组最后一条消息的时间
let lastMessageDate = self[lastGroupIndex].groupDate
PrintLog(message: lastMessageDate)
// 判断当前消息与上条消息的时间差
let timeDifference = messageDate.timeIntervalSince(lastMessageDate)
PrintLog(message: timeDifference)
if timeDifference > interval.timeInterval {
//时间差超过间隔,创建新的分组,groupDate 为该消息时间
self.append((messageDate, [message]))
return true
} else {
// 时间差未超过间隔,继续添加到最后分组
self[lastGroupIndex].messages.append(message)
return false
}
} else {
// 创建新的分组,groupDate 为该消息时间
self.append((messageDate, [message]))
return true
}
}
}
示例模型和调用方式
/// 聊天消息模型
struct ChatMessage {
let id: UUID
let text: String
let timestamp: Date
let senderId: String
}
// 示例使用:按 30 分钟分组
let messages: [ChatMessage] = [...] // 假设你已经有消息数组
let groups = messages.grouped(by: .thirtyMinutes)
// 打印分组结果
for group in groups {
print("时间段:\(group.groupDate)")
for msg in group.messages {
print(" - \(msg.text)")
}
}