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