具有自定义数据结构的 SwiftUI 列表,每个循环都嵌套 [关闭]
Posted
技术标签:
【中文标题】具有自定义数据结构的 SwiftUI 列表,每个循环都嵌套 [关闭]【英文标题】:SwiftUI List with custom data structure with nested for each loops [closed] 【发布时间】:2021-10-31 02:07:16 【问题描述】:我已经能够在我的 swiftui 应用程序中成功实现无限滚动,但它的行为不正确,它与它迭代的列表有关。例如,我从 graphql 端点获取产品订单列表并将其存储为
@Published var groupedPurchaseOrders = [[PurchaseOrderFragment]]()
它嵌套在数组中的原因是因为我将这些数据处理成按订单日期分隔的组。
func groupPurchaseOrders()
let dateGroups = Dictionary(grouping: purchaseOrders) (element) -> Date in
return element.orderForDate.reduceToMonthDayYear()
let sortedKeys = dateGroups.keys.sorted (Date1, Date2) -> Bool in
Date1 > Date2
sortedKeys.forEach key in
let values = dateGroups[key]
groupedPurchaseOrders.append(values)
这样我可以创建一个列表,其中包含带有日期的标题(我从列表中的第一项派生)然后是采购订单。
ForEach(posModel.groupedPurchaseOrders, id: \.self) group in
Section(header: <Derived date from first item>)
ForEach(group, id: \.self) order in
NavigationLink(destination: PurchaseOrderDetailView(purchaseOrder: order))
PurchaseOrderListItemOnlyView(purchaseOrder: order)
.padding(.vertical, 4)
.onAppear
let purchaseOrders = posModel.groupedPurchaseOrders.flatMap $0
if purchaseOrders.last == order
self.loadOrders()
Date
Order
Order
Date
Order
...
问题:
列表可以正常加载前 20 个项目,但是当它到达列表底部并加载更多(在本例中为 5 个项目)时,它会添加 5,列表具有原始的 20 加 25。但是当我创建了一个没有分组的普通列表,它按预期工作,只是将 5 附加到末尾。
作为 ios dev 的初学者,我不确定是否可以创建类似的数据结构 [日期,[PurchaseOrderFragment]] 与 [PurchaseOrderFragment] 相对。我已经尝试过了,但似乎无法正确地获得语法和实现......关于如何通过分组实现列表的任何想法?它在哪里正确附加记录?
编辑:
我试过了
struct GroupedOrder: Hashable
var date: Date
var orders: [PurchaseOrderFragment]
public func hash(into hasher: inout Hasher)
hasher.combine(date)
hasher.combine(orders)
当它再加载 5 个时,它仍然会复制列表
【问题讨论】:
您可以创建一个类型为(Date, [PurchaseOrderFragment])
的元组,但似乎只创建一个包装器会更有意义:struct PurchaseWrapper var date: Date; var orders: [PurchaseOrderFragment]
然后迭代这些.
@jnpdx 我正是这样做的,它只是复制了前 20 个,并在负载上增加了 5 个。您认为这可能是 List 组件的限制吗?
不——它与您的 groupPurchaseOrders
函数有关。你所做的就是append
。我认为您在这里没有足够的信息/代码来诊断逻辑应该是什么,但是您需要确定是否需要替换整个数组,附加到它等等。
列表中有45个元素,但打印出模型中列表的计数,有25个,似乎在列表中
你能加入minimal reproducible example吗?否则无法帮助调试细节。
【参考方案1】:
我根据您的代码编写了一个游乐场。它缺少的是您的代码未显示的“再加载 5 个”的概念。但是分组日期只是由与原始代码相同的Dictionary(grouping: purchaseOrders) $0.date
组成。从理论上讲,您可以使用任何采购订单列表。
`
import UIKit
import SwiftUI
import PlaygroundSupport
let mockPurchaseOrders = """
[
"date" : "1/1/2020", "title": "The First Purchase Order" ,
"date" : "1/1/2020", "title": "The Second Purchase Order" ,
"date" : "1/1/2020", "title": "The Third Purchase Order" ,
"date" : "3/2/2020", "title": "The Fourth Purchase Order" ,
"date" : "3/2/2020", "title": "The Fifth Purchase Order" ,
"date" : "5/1/2020", "title": "The Sixth Purchase Order" ,
"date" : "7/1/2020", "title": "The Seventh Purchase Order" ,
"date" : "7/1/2020", "title": "The Eighth Purchase Order" ,
"date" : "7/1/2020", "title": "The Ninth Purchase Order"
]
"""
struct PurchaseOrder : Decodable, Hashable
static var dateFormatter : DateFormatter =
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
return formatter;
()
let title : String
let date : Date
init(from decoder: Decoder) throws
let container = try decoder.container(keyedBy: Self.CodingKeys)
title = try container.decode(String.self, forKey: CodingKeys.title)
let dateString = try container.decode(String.self, forKey: .date)
date = PurchaseOrder.dateFormatter.date(from: dateString)!
enum CodingKeys: String, CodingKey
case title
case date
typealias GroupedDates = [Date : [PurchaseOrder]]
struct NestedListView : View
let groupedOrders : GroupedDates
var orderDates : [Date] Array<Date>(groupedOrders.keys).sorted()
static var dateFormatter : DateFormatter =
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .none
return formatter;
()
init(orders : GroupedDates)
groupedOrders = orders
var body : some View
ForEach(orderDates, id: \.self) date in
Section(header: Text(NestedListView.dateFormatter.string(from: date)))
ForEach(groupedOrders[date]!, id: \.self) order in
NavigationLink(destination: Text("Hello!"))
Text(order.title)
.frame(minWidth: 320, idealWidth: 320, maxWidth: 320, minHeight: 480)
let jsonDecoder = JSONDecoder()
let purchaseOrders = try jsonDecoder.decode([PurchaseOrder].self, from: mockPurchaseOrders.data(using: .utf8)!)
let groupedOrders = Dictionary(grouping: purchaseOrders) $0.date
let hostingController = UIHostingController(rootView: NestedListView(orders: groupedOrders))
PlaygroundSupport.PlaygroundPage.current.liveView = hostingController
【讨论】:
感谢您发布此内容,非常感谢,但我发现在集合分组功能中我再次获得了整个列表,因此重复,但我从您的示例中学到了很多关于如何重新实现的知识我会检查它作为答案 哎呀!我想我在发布我的解决方案之前大约一个小时错过了你的 cmets!感谢您的客气话,我很高兴这可以帮助您学习。以上是关于具有自定义数据结构的 SwiftUI 列表,每个循环都嵌套 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:禁用具有自定义 ButtonStyle 的 NavigationLink 的最佳方法
SwiftUI:自定义按钮无法识别具有清晰背景和 buttonStyle 的触摸