Home > Mobile >  What is wrong with this API call for SwiftUI
What is wrong with this API call for SwiftUI

Time:02-25

I have been trying to make an API call with swiftui, but I keep running into threading errors when I run the code. This is the current program:

import SwiftUI


struct Post: Codable, Identifiable {
    var id = UUID()
    var title: String
    var body: String
}

class Api {
    func getPosts(){
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else { return}
        URLSession.shared.dataTask(with: url) { data, _, _ in
            let posts = try! JSONDecoder().decode([Post].self, from: data!)
            print(posts)
        }
        .resume()
    }
}

// Content view file
import SwiftUI

struct PostList: View {
    var body: some View {
        Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
            .onAppear{
                Api().getPosts()
            }
    }
}

struct PostList_Previews: PreviewProvider {
    static var previews: some View {
        PostList()
    }
}

I got this code verbatim from a swift tutorial, but I am getting errors from it. Any help would be greatly appreciated!

CodePudding user response:

the problem happen because in this line:

let posts = try! JSONDecoder().decode([Post].self, from: data!)

you are making force unwrap try! and swift can't decode your data into [Post] because your model is wrong, change for this:

struct Post: Codable {
var userId: Int
var id: Int
var title: String
var body: String
}

your app will compile, and please avoid to use force unwrap.

CodePudding user response:

To "fix" your error, use var id: Int in your Post model. Also use the following code, that is more robust than the tutorial code you have been using: see this SO post: Preview Crashed when I get data from api

struct ContentView: View {
    @State var posts: [Post] = []

    var body: some View {
        VStack {
            List(posts) { post in
                Text(post.title)
            }
            .onAppear{
                Api.shared.getPosts { posts in  // <-- here
                    self.posts = posts
                }
            }
        }
    }
}

struct Post: Codable, Identifiable {
    var id: Int  // <-- here
    var title: String
    var body: String
}

class Api {
    
    static let shared = Api()  // <-- here
    
    func getPosts(completion: @escaping([Post]) -> ()) {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else { return
            print("bad url")
        }
        
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else {   // <-- here
                print("no data") // todo deal with no data
                completion([])
                return
            }
            do {
                let posts = try JSONDecoder().decode([Post].self, from: data)
                DispatchQueue.main.async {
                    completion(posts)
                }
                print(posts)
            } catch {
                print("\(error)")
            }
        }
        .resume()
    }
}
  • Related