如何正确地将部分中的项目与 RxDataSource swift 结合起来?
Posted
技术标签:
【中文标题】如何正确地将部分中的项目与 RxDataSource swift 结合起来?【英文标题】:How I can correctly combine items in section with RxDataSource swift? 【发布时间】:2019-10-01 00:57:17 【问题描述】:我需要在一分钟内发送项目时将聊天消息合并到部分中。
视图模型
.....
.scan([MessageSectionModel]()) sectionModels, messageItem in
var models = sectionModels
if let lastSectionModel = sectionModels.last
switch lastSectionModel
case .incomingSection(var items):
if messageItem.0.isIncoming
items.append(messageItem.0)
models[models.count-1] = .incomingSection(items: items)
else
models.append(.outcomingSection(items: [messageItem.0]))
case .outcomingSection(var items):
if messageItem.0.isIncoming
models.append(.incomingSection(items: [messageItem.0]))
else
items.append(messageItem.0)
models[models.count-1] = .outcomingSection(items: items)
return models
if messageItem.0.isIncoming
models.append(.incomingSection(items: [messageItem.0]))
else
models.append(.outcomingSection(items: [messageItem.0]))
return models
.....
视图控制器
....
@IBOutlet private weak var messagesTableView: UITableView!
private let disposeBag = DisposeBag()
private var dataSource: RxTableViewSectionedAnimatedDataSource<MessageSectionModel>!
private let messageHeaderReuseIdentifier = String(describing: MessageHeaderView.self)
private let messageFooterReuseIdentifier = String(describing: MessageFooterView.self)
dataSource = RxTableViewSectionedAnimatedDataSource<MessageSectionModel>(
animationConfiguration: .init(insertAnimation: .none, reloadAnimation: .none, deleteAnimation: .none),
configureCell: dataSource, tableView, indexPath, item in
switch dataSource.sectionModels[indexPath.section]
case .incomingSection:
guard let cell = tableView.dequeueReusableCell(
withIdentifier: R.reuseIdentifier.incomingMessageTableViewCell,
for: indexPath
) else
return UITableViewCell()
let isFirst = indexPath.row == dataSource[indexPath.section].items.count - 1
cell.bind(
messageText: item.text,
isFirstInSection: isFirst
)
return cell
case .userSection:
guard let cell = tableView.dequeueReusableCell(
withIdentifier: R.reuseIdentifier.outcomingMessageTableViewCell,
for: indexPath
) else
return UITableViewCell()
cell.bind(
messageText: item.text,
isFirstInSection: indexPath.row == dataSource[indexPath.section].items.count - 1
)
return cell
)
....
消息项
....
import Foundation
import RxDataSources
enum MessageSectionModel
case incomingSection(items: [MessageSectionItem])
case outcomingSection(items: [MessageSectionItem])
var lastMessageDate: Date
switch self
case .incomingSection(let items):
return items.last?.sentDate ?? Date()
case .outcomingSection(let items):
return items.last?.sentDate ?? Date()
struct MessageSectionItem
let userId: String
let id: String = UUID().uuidString
let text: String
let sentDate: Date
let isIncoming: Bool
extension MessageSectionItem: IdentifiableType
var identity : String
return id
extension MessageSectionItem: Equatable
static func == (lhs: MessageSectionItem, rhs: MessageSectionItem) -> Bool
return lhs.identity == rhs.identity
extension MessageSectionModel: AnimatableSectionModelType
init(original: MessageSectionModel, items: [MessageSectionItem])
switch original
case .incomingSection(let items):
self = .incomingSection(items: items)
case .outcomingSection(let items):
self = .outcomingSection(items: items)
typealias Item = MessageSectionItem
var items: [MessageSectionItem]
switch self
case .incomingSection(let items):
return items.map $0
case .outcomingSection(let items):
return items.map $0
var identity: Date
return lastMessageDate
....
我的表格视图被旋转,因为我获取消息被还原。我知道这是我的扫描错误,因为当我收到此代码时,我的单元格以正确的方式排序,但没有按部分组合。
if let lastSectionModel = sectionModels.last
switch lastSectionModel
case .incomingSection(var items):
if messageItem.0.isIncoming
items.append(messageItem.0)
models[models.count-1] = .incomingSection(items: items)
else
models.append(.outcomingSection(items: [messageItem.0]))
case .outcomingSection(var items):
if messageItem.0.isIncoming
models.append(.incomingSection(items: [messageItem.0]))
else
items.append(messageItem.0)
models[models.count-1] = .outcomingSection(items: items)
return models
【问题讨论】:
【参考方案1】:我认为您一次尝试做太多事情,而且顺序错误。将工作分解成更小的工作,每个工作都可以轻松测试/验证...另外,首先按时间对消息进行分组,然后将它们放在你的部分中。我最终得到了这个:
struct MessageItem
let userId: String
let id: String = UUID().uuidString
let text: String
let sentDate: Date
let isIncoming: Bool
struct MessageGroup
let userId: String
var text: String
return parts.map $0.text .joined(separator: "\n")
let isIncoming: Bool
struct Part
let id: String
let text: String
let sentDate: Date
init(_ messageSectionItem: MessageItem)
id = messageSectionItem.id
text = messageSectionItem.text
sentDate = messageSectionItem.sentDate
var parts: [Part]
init(from item: MessageItem)
userId = item.userId
isIncoming = item.isIncoming
parts = [Part(item)]
enum MessageSectionModel
case incomingSection(items: [MessageGroup])
case outcomingSection(items: [MessageGroup])
extension ObservableType where Element == MessageItem
func convertedToSectionModels() -> Observable<[MessageSectionModel]>
return
scan(into: ([MessageGroup](), MessageGroup?.none), accumulator: groupByTime(messages:item:))
.map(appendingLastGroup(messages:group:))
.map(groupedByIncoming(messages:))
.map(convertedToSectionModels(messages:))
func groupByTime(messages: inout ([MessageGroup], MessageGroup?), item: MessageItem)
if let group = messages.1
let lastPart = group.parts.last!
if lastPart.sentDate.timeIntervalSince(item.sentDate) > -60 && group.userId == item.userId
messages.1!.parts.append(MessageGroup.Part(item))
else
messages.0.append(group)
messages.1 = MessageGroup(from: item)
else
messages.1 = MessageGroup(from: item)
func appendingLastGroup(messages: [MessageGroup], group: MessageGroup?) -> [MessageGroup]
guard let group = group else return messages
return messages + [group]
func groupedByIncoming(messages: [MessageGroup]) -> [[MessageGroup]]
return messages.reduce([[MessageGroup]]()) result, message in
guard let last = result.last else
return [[message]]
if last.last!.isIncoming == message.isIncoming
return Array(result.dropLast()) + [last + [message]]
else
return result + [[message]]
func convertedToSectionModels(messages: [[MessageGroup]]) -> [MessageSectionModel]
messages.map messages in
if messages.first!.isIncoming
return .incomingSection(items: messages)
else
return .outcomingSection(items: messages)
【讨论】:
以上是关于如何正确地将部分中的项目与 RxDataSource swift 结合起来?的主要内容,如果未能解决你的问题,请参考以下文章
如何正确地将 Kal 框架添加到我的 iPhone 项目中?
CMake项目结构:如何正确地将库合并在一起并将它们包含在多个可执行文件中
如何正确地将 OData 与 ASP.net Core 集成