Search code examples
swiftswiftuiswift3

What is wrong with this API call for SwiftUI


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!


Solution

  • 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()
        }
    }