首页 > 解决方案 > 无法从 REST API 读取 JSON

问题描述

尝试读取此 JSON 数据:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

但是我的应用程序不断崩溃,我很难理解原因(对于 swift 来说还是相当新的)。我认为数据存储在字典中,我只是处理不正确。有人可以解释一下解码这个 JSON 的正确方法以及我将如何在视图上显示它吗?我尝试用 JSONSerialization 代替 JSONDecoder 但得到了相同的结果,所以不确定这是否是正确的方向。

模型:

struct Model: Codable{
        var userId: Int? = nil
        var id: Int? = nil
        var title: String? = nil
        var completed: Bool? = nil
        
        enum CodingKeys: CodingKey{
           case userId, id, title, completed
        }
}

JSON加载函数:

func loadData(){
        let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")!
        
        //create url request
        var request = URLRequest(url: url)
        
        //specify the method to use
        request.httpMethod = "GET"
        
        //set HTTP request Header, can set more than one.
        request.setValue("application/json", forHTTPHeaderField: "Accept")

        //send the request
        
        let dataTask = URLSession.shared.dataTask(with: request){ data, response, error in
            
            if let data = data{
                if let users = try? JSONDecoder().decode(Model.self, from: data){
                   
                    DispatchQueue.main.async {
                        self.dataInfo = users
                    }
                }else{
                    print("Data Not Got")
                }
                
                
            }
            
            if let response = response{
                print("Response Got")
            }
            
            if let error = error{
                print("\(error)")
            }
        }
        dataTask.resume()
    }

斯威夫特用户界面视图:

struct ContentView: View {
    @State var dataInfo = Model()
    
    var body: some View {
        VStack{
            Button("Go"){
                loadData()
            }
            Text(dataInfo.title!)
}

标签: jsonswiftswiftui

解决方案


通过使用!after title,您正在执行所谓的“强制展开” - 告诉系统尽管变量/属性被声明为 Optional(在这种情况下String?),但您将保证它不nil存在并且存在实际上是一个值。问题是,在您完成 API 调用之前,该属性实际上nil导致您的程序崩溃的。

这是更改它的一种方法(说明如下):

struct Model: Codable{
    var userId: Int
    var id: Int
    var title: String
    var completed: Bool
}

struct ContentView: View {
    @State var dataInfo : Model?
    
    var body: some View {
        VStack{
            Button("Go"){
                loadData()
            }
            if let dataInfo = dataInfo {
                Text(dataInfo.title)
            }
        }
    }
    
    func loadData() {
     // your previous code here
    } 
}

在这个版本中,dataInfo是一个 Optional,它在 API 调用时被设置。然后,if let dataInfo = dataInfo做一些叫做“可选绑定”的事情,基本上告诉系统只在dataInfo不是nil.

最后,我已将您更改Model为具有非可选属性,因为您使用的 API 调用返回所有这些字段的值。如果您想保留以前的模型,您可能希望将我的代码更改为:

if let title = dataInfo?.title {
    Text(title)
}

查看 Swift 编程语言书籍以获取有关 Optionals 以及如何使用它们的更多信息:https ://docs.swift.org/swift-book/LanguageGuide/TheBasics.html


推荐阅读