{
"data":{
"email":"[email protected]",
"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")
}
}
}
i need to know if the codable structure is right according to the structure of data i gave ? and also the fetching in list ? please i need help in the URLsession i am still new and i barely know about url alot !
i would be grateful if you help me ! thank you verrrry much !!!!
CodePudding user response:
In the JSON there is no array involved (no []
at all).
The model corresponding to the JSON is
struct Response: Decodable {
let data : UserData
}
struct UserData: Decodable {
let email: String
let password: String
let token: String
}
So the data source cannot be declared as an array. To avoid an optional type create an enum with associated values indicating a state. The benefit is that you can show different views depending on the state
struct JsonResult: View {
enum LoadingState {
case idle, loading, loaded(UserData), failure(Error)
}
this is the rest of the struct, consider that there is no List
either because UserData
is a single object.
@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
}
}
}
CodePudding user response:
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, response) = try? await URLSession.shared.data(from: url) else{throw RequestError.invalidURL}
guard (response 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.append(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")
}
}
})
}
}