简体   繁体   English

在 Swift 5 中解码 JSON 后得到 nil

[英]Getting nil after decoding JSON in Swift 5

@Edit - Thanks to the do-try-catch suggestion from Finn, it turned out Json was containing some null values, which I had missed during testing in postman. After refactoring fields in UserInfoStruct to Optionals, everything works. @Edit - 感谢 Finn 的do-try-catch建议,结果 Json 包含一些null值,我在 postman 的测试中错过了这些值。将UserInfoStruct中的字段重构为 Optionals 后,一切正常。

I'm trying to unwrap json in my application, but despite getting code 200 from server and receiving bytes of data, printing returns nil .我试图在我的应用程序中解包 json,但尽管从服务器获取代码200并接收数据字节,打印返回nil Putting field in struct that returns string with all the information resulted with nil as well, same with printing one of the fields.将字段放入返回字符串的结构中,所有信息也都为nil ,与打印其中一个字段相同。 I've followed tutorials like the one on hackingwithswift.com, but to no avail.我已经遵循了 hackingwithswift.com 之类的教程,但无济于事。 Previously checking on reqres.in endpoints, everything works just fine.之前检查 reqres.in 端点,一切正常。

Code used to fetch data from api with the build-in json decoder:用于使用内置 json 解码器从 api 获取数据的代码:

func getUserInfo() {
        var userInfo: UserInfoStruct?
        let token = UserDefaults.standard.string(forKey: ApiUtils().userToken) ?? ""
        guard let url = URL(string: EndpointUrls().machineUrl + EndpointUrls().profileUrl) else { return }
        var request = URLRequest(url: url)
        request.httpMethod = HttpMethodsStruct().get
        request.setValue(ApiUtils().appjson, forHTTPHeaderField: ApiUtils().contType)
        request.addValue(ApiUtils().bearer + token, forHTTPHeaderField: ApiUtils().auth)
        URLSession.shared.dataTask(with: request) {data, response, error in
            let httpStatusCode = (response as? HTTPURLResponse)?.statusCode ?? 0
            print(httpStatusCode)
            if (httpStatusCode) == 200 {
                if let data = data {
                    print(data)
                    userInfo = try? JSONDecoder().decode(UserInfoStruct.self, from: data)
                    print(userInfo)
                }
            }
        }.resume()
    }

I've replaced all the strings with variables declared in another struct, as some of them are used in the more places.我用另一个结构中声明的变量替换了所有字符串,因为其中一些在更多地方使用。 With this, any changes would be easier to implement.这样,任何更改都将更容易实施。 To access the endpoints, You need to be logged in a specific vpn.要访问端点,您需要登录特定的 vpn。

Here is the example json I'm receiving:这是我收到的示例 json:

{
  "authorities": [
    {
      "created_at": "2021-01-21T13:49:32.755Z",
      "id": 0,
      "name": "string",
      "updated_at": "2021-01-21T13:49:32.755Z"
    }
  ],
  "business_name": "string",
  "created_at": "2021-01-21T13:49:32.755Z",
  "devices_limit": 0,
  "email": "string",
  "first_name": "string",
  "has_active_call": true,
  "id": 0,
  "is_business_account": true,
  "last_name": "string",
  "marketing": true,
  "min_to_call": 0,
  "paid_to": "2021-01-21T13:49:32.755Z",
  "password_reset_active_link": true,
  "phone_number": "string",
  "translation_types": [
    {
      "display_name": "string",
      "id": 0,
      "jabber_destination": "string",
      "name": "string"
    }
  ],
  "updated_at": "2021-01-21T13:49:32.755Z"
}

Using app.quicktype.io, following structs has been generated:使用 app.quicktype.io,生成了以下结构:


import Foundation

struct UserInfoStruct: Codable {
    let authorities: [Authority]
    let business_name: String
    let created_at: String
    let devices_limit: Int
    let email: String
    let first_name: String
    let has_active_call: Bool
    let id: Int
    let is_business_account: Bool
    let last_name: String
    let marketing: Bool
    let min_to_call: Int
    let paid_to: String
    let password_reset_active_link: Bool
    let phone_number: String
    let translation_types: [TranslationType]
    let updated_at: String
}

struct Authority: Codable {
    let created_at: String
    let id: Int
    let name: String
    let updated_at: String
}

struct TranslationType: Codable {
    let display_name: String
    let id: Int
    let jabber_destination: String
    let name: String
}

Still, in console all, that's printed, is this:不过,在控制台中,打印出来的是这样的:

200        <- from print(httpStatusCode)
689 bytes  <- from print(data)
nil        <- from print(userInfo)

As in some tutorials, I've tried to declare userInfo field as在某些教程中,我尝试将 userInfo 字段声明为

var userInfo = [UserInfoStruct]()

but it only resulted in但这只会导致

Cannot assign value of type 'UserInfoStruct?'无法分配“UserInfoStruct”类型的值? to type '[UserInfoStruct]'输入“[UserInfoStruct]”

Declaring this field both in the func as well as @State in the main struct gave the same results.在 func 和主结构中的@State中声明此字段给出了相同的结果。

About me: I'm self-taught with background in java. I've been developing in swift since October 2020, so I'm fully aware, that many problems might be trivial and my lack of experience causes me to miss them.关于我:我是java背景自学的,2020年10月开始在swift开发,所以我深知,很多问题可能都是小问题,经验不足导致我错过。

Thanks for all the help.感谢所有的帮助。

You can try catching your errors with a do-catch block instead of just using try?您可以尝试使用do-catch块来捕获错误,而不仅仅是使用try? . . This will enable you to log a error message instead if just getting a nil result.如果只是得到一个nil结果,这将使您能够记录一条错误消息。

a do-catch block is formed like this:一个 do-catch 块是这样形成的:

do {
    userInfo = try JSONDecoder().decode(UserInfoStruct.self, from: data)
    print("Success!")
} catch {
    print("Unexpected error: \(error).")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM