提问人:Nus 提问时间:10/26/2023 最后编辑:Nus 更新时间:10/26/2023 访问量:87
Swift UI 视图仅显示一条记录,而不是记录列表
Swift UI view only displaying one record instead of the List of record
问:
我正在使用 Swift UI 。我正在使用 async 和 await 来处理并发。我正在尝试显示产品记录列表。我有 30 条记录进入 json,这里是 json 链接 https://dummyjson.com/products。我在调试时得到了 30 条记录,但是当我运行应用程序时,它只显示一条记录。我想知道错误或更改在哪里,我需要做出。
这是我的模型..
import Foundation
// MARK: - Welcome
struct ProductData: Codable, Hashable {
let products: [Product]
}
// MARK: - Product
struct Product: Codable, Hashable {
let id: Int
let title, description: String
let price: Int
let discountPercentage, rating: Double
let stock: Int
let brand, category: String
let thumbnail: String
let images: [String]
}
这是我的观点模型代码。
@MainActor
final class ProductListViewModel {
@Published private(set) var productLists: [ProductData] = []
@Published private(set) var customError: NetworkError?
@Published private(set) var refreshing = true
@Published var isErrorOccured = false
private let repository: ProductRepository
init(repository: ProductRepository) {
self.repository = repository
}
}
extension ProductListViewModel: ProductListViewModelAction {
func getProductList(urlStr: String) async {
refreshing = true
guard let url = URL(string: urlStr) else {
self.customError = NetworkError.invalidURL
refreshing = false
isErrorOccured = false
return
}
do {
let lists = try await repository.getList(for: url)
refreshing = false
isErrorOccured = false
productLists = [lists]
} catch {
refreshing = false
isErrorOccured = true
customError = error as? NetworkError
}
}
}
这是我的观点.
import SwiftUI
struct ProductListView: View {
@StateObject var viewModel = ProductListViewModel(repository: ProductRepositoryImplementation(networkManager: NetworkManager()))
var body: some View {
NavigationStack {
VStack {
if viewModel.customError != nil && !viewModel.refreshing {
alertView()
} else {
if viewModel.refreshing {
progressView()
}
if viewModel.productLists.count > 0 && !viewModel.refreshing {
List(viewModel.productLists, id: \.self) { product in
ProductListViewCell(productData: product)
} .listStyle(.grouped)
}
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
getToolBarView()
}
}
.navigationTitle(Text("Product List"))
}.task{
await getDataFromAPI()
}
.refreshable {
await getDataFromAPI()
}
}
func getDataFromAPI() async {
await viewModel.getProductList(urlStr: NetworkURL.productUrl)
}
@ViewBuilder
func getToolBarView() -> some View {
Button {
Task{
await getDataFromAPI()
}
} label: {
HStack {
Image(systemName: "arrow.clockwise")
.padding(.all, 10.0)
}.fixedSize()
}
.cornerRadius(5.0)
}
@ViewBuilder
func progressView() -> some View {
VStack{
RoundedRectangle(cornerRadius: 15)
.fill(.white)
.frame(height: 180)
.overlay {
VStack {
ProgressView().padding(50)
Text("Please Wait Message").font(.headline)
}
}
}
}
@ViewBuilder
func alertView() -> some View {
Text("").alert(isPresented: $viewModel.isErrorOccured) {
Alert(title: Text("General_Error"), message: Text(viewModel.customError?.localizedDescription ?? ""),dismissButton: .default(Text("Okay")))
}
}
}
这是我的单元格视图..
import SwiftUI
struct ProductListViewCell: View {
let productData: ProductData
var body: some View {
HStack {
if let url = URL(string: productData.products.first?.thumbnail ?? ""){
ProductAsyncImageView(url: url)
.frame(width: 150, height: 150)
.mask(RoundedRectangle(cornerRadius: 16))
}
VStack(alignment: .leading,spacing: 5){
Text("Product Name: " + (productData.products.first?.title ?? ""))
.frame(maxWidth: .infinity, alignment: .leading)
.font(.headline)
Text("Product Description: " + (productData.products.first?.description ?? ""))
.frame(maxWidth: .infinity, alignment: .leading)
Text("Product Price: " + String(productData.products.first?.price ?? 0))
.frame(maxWidth: .infinity, alignment: .leading)
.font(.subheadline)
}
}
}
}
这是调试中的结果。
这是屏幕截图..仅显示一条记录。
答:
2赞
Rob
10/26/2023
#1
创建一个包含一个项目的数组。现在,其中可能有 30 个产品,但随后仅为其中的第一个产品创建一个单元格。因此,将只显示一个项目。productLists = [lists]
ProductData
ProductListViewCell
ProductData
我建议产品列表视图模型可能只采用一系列产品:
final class ProductListViewModel: ObservableObject {
@Published private(set) var products: [Product] = [] // an array of products
…
}
extension ProductListViewModel {
func getProductList(urlStr: String) async {
refreshing = true
guard let url = URL(string: urlStr) else { … }
do {
let productList = try await repository.getList(for: url)
refreshing = false
isErrorOccured = false
products = productList.products // get the list of products
} catch {
…
}
}
}
然后将显示以下数组:ProductListView
Product
struct ProductListView: View {
@StateObject var viewModel = …
var body: some View {
NavigationStack {
VStack {
…
if viewModel.products.count > 0 && !viewModel.refreshing {
List(viewModel.products, id: \.self) { product in
ProductListViewCell(product: product)
} .listStyle(.grouped)
}
}
}
然后,该单元格只需:Product
struct ProductListViewCell: View {
let product: Product
var body: some View {
HStack {
if let url = URL(string: product.thumbnail) { … }
VStack(alignment: .leading, spacing: 5) {
Text("Product Name: \(product.title)")
.frame(maxWidth: .infinity, alignment: .leading)
.font(.headline)
Text("Product Description: \(product.description)")
.frame(maxWidth: .infinity, alignment: .leading)
Text("Product Price: \(product.price)")
.frame(maxWidth: .infinity, alignment: .leading)
.font(.subheadline)
}
}
}
}
屈服:
现在,有很多方法可以给猫剥皮:如果你愿意,你可以使用你的。但关键的要点信息是,用于显示单个,因此给它一个整体并且仅访问包含在 .ProductData
ProductListViewCell
Product
ProductData
first
ProductData
评论