在 URL 会话中获取嵌套的 json?

Get a nested json in URL session?

{
"data":{
"email":"ms.lightwave@example.com", 
"password":"123",
"token":""
} 
}



struct JsonResult: View{
    @State private var results = [GetData]()
    var body: some View{
        List(results, id: \.email){ item in
            VStack(alignment: .leading) {
                Text(item.password)
                    .font(.headline)
                Text(item.token)
                    .font(.headline)
            }
            
        }.task {
            await loadData()
        }
    }

struct Response : Codable {
        var results: [GetData]
    }
    
    struct GetData: Codable{
        var data : [Result]
    }
    
    struct Result: Codable {
        var email: String
        var password: String
        var token: String
    }
    func loadData() async{
        guard let url = URL(string: "MYURL") else {
            print("invalid URL")
            return
        }
        do{
            let(data,_) = try await URLSession.shared.data(from: url)
            // more code
            if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data)
            {
                results = decodedResponse.results
            }
        } catch {
            print("Invalid Data")
        }
    }

}

我需要知道根据我提供的数据结构,可编码结构是否正确?还有列表中的获取?请在 URLsession 中需要帮助我还是新手,我对 url 几乎一无所知!

如果你能帮助我,我将不胜感激!非常感谢你 !!!!

struct Response : Decodable, Hashable {
    var results: [GetData]
}

struct GetData: Decodable, Hashable{
    var data : [Result]
}

struct Result: Decodable, Hashable {
    var email: String
    var password: String
    var token: String
}

enum RequestError: Error {
    case invalidURL
    case missingData
}

class JsonResultViewModel: ObservableObject{
    
    @Published var response = [Response]()
    
    func performHTTPRequest(urlString: String) async throws{
        guard let url = URL(string: urlString) else {throw RequestError.invalidURL}
        guard let (data, resp) = try? await URLSession.shared.data(from: url) else{throw RequestError.invalidURL}
        guard (resp as? HTTPURLResponse)?.statusCode == 200 else {throw RequestError.invalidURL}
        let decoder = JSONDecoder()
        guard let jsonResponse = try? decoder.decode([Response].self, from: data) else {throw RequestError.missingData}
        DispatchQueue.main.async {
           self.response = jsonResponse 
        }
    }
}



struct ContentView: View {
    @StateObject private var results = JsonResultViewModel()
    var body: some View {
        List(results.response.indices, id: \.self){ index in
            VStack(alignment: .leading) {
                Text(results.response[index].results[index].data[index].email)
                    .font(.headline)
                Text(results.response[index].results[index].data[index].token)
                    .font(.headline)
            }
        }
        .onAppear(perform: {
            Task{
                do {
                    try await results.performHTTPRequest(urlString: "wwww.url.com")
                } catch RequestError.invalidURL{
                    print("invalid URL")
                } catch RequestError.missingData{
                    print("missing data")
                }
            }
        })
        
    }
}

在 JSON 中没有涉及数组(根本没有 [])。

JSON对应的机型是

struct Response: Decodable {
    let data : UserData
}

struct UserData: Decodable {
    let email: String
    let password: String
    let token: String
}

所以数据源不能声明为数组。要避免可选类型,请创建一个枚举,其关联值指示 state。好处是可以根据状态显示不同的视图

struct JsonResult: View {

    enum LoadingState {
        case idle, loading, loaded(UserData), failure(Error)
    }

这是结构的其余部分,请考虑也没有 List 因为 UserData 是单个对象。

    @State private var state : LoadingState = .idle
    
    var body: some View {
        VStack {
            switch state {
                case .idle: EmptyView()
                case .loading: ProgressView()
                case .loaded(let userData):
                    
                    VStack(alignment: .leading) {
                        Text(userData.password)
                            .font(.headline)
                        Text(userData.email)
                            .font(.headline)
                    }
                    
                case .failure(let error): Text(error.localizedDescription)
            }
        }.task {
            await loadData()
        }
    }
    
    func loadData() async {
        
        state = .loading
        guard let url = URL(string: "MYURL") else {
            state = .failure(URLError(.badURL))
            return
        }
        do {
            let (data,_) = try await URLSession.shared.data(from: url)
            // more code
            let decodedResponse = try JSONDecoder().decode(Response.self, from: data)
            state = .loaded(decodedResponse.data)
            
        } catch {
            state = .failure(error)
            print(error) // this shows the real DecodingError
        }
    }
}