首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在SwiftUI中从API中获取值(而不是数组)

如何在SwiftUI中从API中获取值(而不是数组)
EN

Stack Overflow用户
提问于 2022-04-05 18:38:42
回答 1查看 211关注 0票数 -1

我使用这个API:https://api.spacexdata.com/v4/rockets。通过一些探索,我决定使用这个API getter:

代码语言:javascript
复制
let rocketsData: [Rocket] = [] //<-- Spoiler: This is my problem

class Api {
    func getRockets(completion: @escaping ([Rocket]) -> ()) {
        guard let url = URL(string: "https://api.spacexdata.com/v4/rockets") else { return }
            
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            do {
                let rockets = try JSONDecoder().decode([Rocket].self, from: data!)
                DispatchQueue.main.async {
                    completion(rockets)
                }
            } catch {
                print(error.localizedDescription)
            }
        }
        .resume()
    }
}

这是我的模型:

代码语言:javascript
复制
struct StageInfo: Codable {
    let engines: Int
    let fuelAmountTons: Double
    let burnTimeSec: Int?
        
    enum CodingKeys: String, CodingKey {
        case engines
        case fuelAmountTons = "fuel_amount_tons"
        case burnTimeSec = "burn_time_sec"
    }
}
    
struct Rocket: Codable, Identifiable {
    let id = UUID()
    let name: String
    let firstFlight: String
    let country: String
    let costPerLaunch: Int
    let firstStage: StageInfo
    let secondStage: StageInfo
            
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case firstFlight = "first_flight"
        case country
        case costPerLaunch = "cost_per_launch"
        case firstStage = "first_stage"
        case secondStage = "second_stage"
    }
}

通过这个模型,我可以得到一个值数组,并且我可以在我的视图中使用这个数组,只包含列表或ForEach循环。但是,如果我想使用的不是数组,而是一些值呢?例如,在这个视图中,我使用了ForEach循环,这就是为什么所有操作都很完美的原因:

代码语言:javascript
复制
    struct ContentView: View {
        @State var rockets = [Rocket]() // <-- Here is the array I was talking about
        
        var body: some View {
            NavigationView {
                List {
                    ForEach(rockets) { item in // <-- ForEach loop to get values from the array
                        NavigationLink(destination: RocketDetailView(rocket: item)) {
                            RocketRowView(rocket: item)
                                .padding(.vertical, 4)
                        }
                    }
                } //: LIST
                .navigationTitle("Rockets")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: {
                            isShowingSettings = true
                        }) {
                            Image(systemName: "slider.horizontal.3")
                        } //: BUTTON
                        .sheet(isPresented: $isShowingSettings) {
                            SettingsView()
                        }
                    }
                } //: TOOLBAR
            } //: NAVIGATION
            .onAppear() {
                Api().getRockets { rockets in // <-- Method to get the array from the API
                    self.rockets = rockets
                }
            }
        }
    }

    //MARK: - PREVIEW
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }

最后,我有一个视图,其中包含一个用于创建的项,即中的列表,另一个视图

代码语言:javascript
复制
    struct RocketRowView: View {
        var rocket: Rocket // <-- Here I don't need to use an array as previously, so I create a usual variable with Rocket instance
        
        var body: some View {
            HStack {
                Image("Falcon-9")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 80, height: 80, alignment: .center)
                    .background(Color.teal)
                    .cornerRadius(8)
                
                VStack(alignment: .leading, spacing: 5) {
                    Text(rocket.name) // <-- So this surely doesn't work
                        .font(.title2)
                        .fontWeight(.bold)
                    Text(rocket.country) // <-- And this doesn't work neither
                        .font(.caption)
                        .foregroundColor(Color.secondary)
                }
            } //: HSTACK <-- And I can't use here inside onAppear the method that I used before to get the array, because I don't need the array
        }
    }

struct RocketRowView_Previews: PreviewProvider {
    static var previews: some View {
        RocketRowView(rocket: rocketsData[0]) // <-- Because of the variable at the top of this View I have to add missing argument for parameter 'rocket' in call. Immediately after that I get an error: "App crashed due to an out of range index"
    }
}

正如我在上面的注释中所写的,我在我的()中创建了一个类型为Rocket的可变的火箭,因此我不得不在RocketRowView_Previews中为参数‘火箭’添加缺少的参数参数。这里我得到了一个错误:“应用程序崩溃是因为超出范围的索引”。我不明白为什么让rocketsData: rocketsData= []是空的,以及如何在视图中使用火箭变量而不用ForEach循环。亲爱的专家们,请帮帮我。我已经绞尽脑汁想出整整一周了,该怎么做。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-06 05:01:07

预览区域中的数据与接收到的数据无关。如果您想要预览,则必须提供自定义实例。

通常的方法是向结构中添加一个静态example属性,如下所示

代码语言:javascript
复制
struct StageInfo: Codable {
    let engines: Int
    let fuelAmountTons: Double
    let burnTimeSec: Int?
        
    enum CodingKeys: String, CodingKey {
        case engines
        case fuelAmountTons = "fuel_amount_tons"
        case burnTimeSec = "burn_time_sec"
    }

    static let firstStage = StageInfo(engines: 1, fuelAmountTons: 44.3, burnTimeSec: 169)
    static let secondStage = StageInfo(engines: 1, fuelAmountTons: 3.30, burnTimeSec: 378)

} 

struct Rocket: Codable, Identifiable {
    let id = UUID()
    let name: String
    let firstFlight: String
    let country: String
    let costPerLaunch: Int
    let firstStage: StageInfo
    let secondStage: StageInfo
            
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case firstFlight = "first_flight"
        case country
        case costPerLaunch = "cost_per_launch"
        case firstStage = "first_stage"
        case secondStage = "second_stage"
    }

    static let example = Rocket(id: UUID(), name: "Falcon 1", firstFlight: "2006-03-24", country: "Republic of the Marshall Islands", costPerLaunch: 6700000, firstStage: StageInfo.firstStage, secondStage: StageInfo.secondStage)

}

然后只需参考下面的例子

代码语言:javascript
复制
struct RocketRowView_Previews: PreviewProvider {
    static var previews: some View {
        RocketRowView(rocket: Rocket.example)
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71756858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档