我进行了一个API调用,该调用返回用于填充视图中使用的数据的数据。我该如何在应用程序打开之前进行调用,以及使用getProducts((存储/返回的数据在其他视图中使用。
我有一个可编码结构,它解析由以下代码调用的JSON数据。可编码数据模型和以下函数位于一个名为Loaders的文件中。
func getProducts() -> [ProductResponse]{
var products: [ProductResponse] = []
if let apiUrl = URL(string: "https://assessment-edvora.herokuapp.com") {
var request = URLRequest(url: apiUrl)
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { (data, response, error) in
do{
let productsFromApi = try JSONDecoder().decode([ProductResponse].self, from: data!)
products = productsFromApi
print(products)
}catch let err{
print(err)
}
}.resume()
}
return products
}
目前,函数是按原样调用的,并且数据被正确地返回和解析。
struct ContentView: View {
var body: some View {
Text("Welcome")
.onAppear(perform: {
getProducts()
})
}
struct ProductCardView: View {
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.white)
.cornerRadius(15)
.shadow(color: Color(.sRGB, red: 0, green: 0, blue: 0, opacity: 0.5), radius: 4, x: -5, y: 5)
VStack(alignment: .leading) {
Spacer()
HStack {
Text("products.id")
.foregroundColor(.black)
.bold()
.padding([.top, .leading])
.font(.largeTitle)
.multilineTextAlignment(.leading)
Spacer()
}
Text("products.description")
.foregroundColor(.black)
.italic()
.padding(.leading)
Spacer()
Image("products.image")
.resizable()
.scaledToFit()
.padding()
}
}
.padding()
}
}
JSON数据是一组产品。我想使用ProductCard视图在卡中显示每个产品,在文本字段中,我想使用product.description等属性。我尝试在Loaders文件中使用ObservableObject,但作为swift的新手,我不确定从哪里开始学习。
最终,每个产品卡都将显示在一个水平滚动列表中。
您的单曲"真理之源";显示为ContentView。您应该为此使用ViewModel,并使用@StateObject进行观察(https://www.hackingwithswift.com/quick-start/swiftui/what-is-the-stateobject-property-wrapper)
示例视图模型:
class ContentViewModel: ObservableObject {
@Published var products: [ProductResponse] // @Published notifies the view when it changes (once network call is done)
func fetch() {
// your existing code
}
}
示例用法:
struct ContentView: View {
@StateObject var vm = ContentViewModel() // @StateObject subscribes to the changes (when network call finishes)
var body: some View {
Text("Welcome")
.onAppear(perform: {
vm.fetch()
})
}
在ContentView中,使用ForEach
迭代产品,并为每个产品创建一个ProductCardView
。这个想法是在ProductCardView中不应该有网络调用,将数据作为参数传入:
struct ProductCardView: View {
let product: ProductResponse // this gets populated from the initializer (see below)
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.white)
.cornerRadius(15)
.shadow(color: Color(.sRGB, red: 0, green: 0, blue: 0, opacity: 0.5), radius: 4, x: -5, y: 5)
VStack(alignment: .leading) {
Spacer()
HStack {
Text(product.id)
.foregroundColor(.black)
.bold()
.padding([.top, .leading])
.font(.largeTitle)
.multilineTextAlignment(.leading)
Spacer()
}
Text(product.description)
.foregroundColor(.black)
.italic()
.padding(.leading)
Spacer()
Image(product.img) // you may need to find a solution to show image from network
.resizable()
.scaledToFit()
.padding()
}
}
.padding()
}
}
这样使用:
ForEach(vm.products) { product in
ProductCardView(product: product) // pass it in
}
你可以把它放在任何你想要的布局
至于在应用程序启动前加载内容,请查看后台获取。一种方法是在磁盘上缓存json。