Swift:如何将两个关联实体合并到一个列表并按日期/类型排序?
解决方案
原代码问题分析
你写的代码有几个关键问题:
ForEach无法直接接收两个数组作为数据源,必须先将两个数组合并为一个统一的集合- 直接通过
transaction.purchaseArray.name访问属性是错误的——purchaseArray是数组类型,你需要访问数组中单个元素的属性,而非数组本身的属性 - 缺少合并后数据的排序逻辑
正确实现步骤
我们可以通过创建一个统一的包装类型,将PurchaseEntity和SellEntity统一处理,再完成合并与排序:
1. 定义统一的交易包装类型
创建枚举来包装两种交易实体,同时提供统一的属性访问方法,方便后续排序和展示:
enum TransactionItem { case purchase(PurchaseEntity) case sell(SellEntity) // 统一获取日期(用于排序) var date: Date { switch self { case .purchase(let p): return p.date ?? Date() case .sell(let s): return s.date ?? Date() } } // 统一获取交易类型 var type: String { switch self { case .purchase: return "Purchase" case .sell: return "Sell" } } // 统一获取名称 var name: String { switch self { case .purchase(let p): return p.name ?? "" case .sell(let s): return s.name ?? "" } } // 统一获取值 var value: String { switch self { case .purchase(let p): return p.value ?? "" case .sell(let s): return s.value ?? "" } } }
2. 在View中合并并排序数据
在你的DetailView中,通过计算属性完成两个数组的合并,以及按日期/类型排序:
struct DetailView: View { @StateObject var transaction: TransactionEntity // 注意:这里应该是TransactionEntity而非Transaction // 合并并排序后的交易列表 var combinedTransactions: [TransactionItem] { // 将两个实体数组转换为统一的TransactionItem类型 let purchases = transaction.purchaseArray.map { TransactionItem.purchase($0) } let sells = transaction.sellArray.map { TransactionItem.sell($0) } // 合并数组 let combined = purchases + sells // 按日期升序排序(如果要按类型排序,替换下方的排序逻辑即可) return combined.sorted { // 按日期排序:$0.date < $1.date 是升序,反过来是降序 $0.date < $1.date // 如果需要按交易类型排序(Purchase在前,Sell在后),使用下面的代码: // $0.type < $1.type } } var body: some View { List(combinedTransactions, id: \.self) { item in VStack(alignment: .leading) { Text(item.name) Text(item.value) Text("\(item.date.formatted(date: .abbreviated, time: .omitted)) \(item.type)") } } } }
3. 额外说明
- 如果你的Core Data关系属性
purchaseArray/sellArray是Set类型(默认生成的关系是Set),需要先转换为数组:Array(transaction.purchaseArray) - 日期格式化可以根据需求调整
formatted的参数,比如你示例中的01.01.2022格式可以用:Text(item.date.formatted(.dateTime.day().month().year()))
内容的提问来源于stack exchange,提问作者SPR
相关产品推荐
相关产品推荐

