簡體   English   中英

使用可編碼協議解析 JSON

[英]Using codable protocol to parse JSON

無法讀取數據,因為它的格式不正確。 嘗試解析下面給出的 JSON。 將數據對象也包含在結構中時引發錯誤

我的 JSON

{
    "status": 200,
    "message": "Logged in successfully.",
    "error_message": [],
    "data": {
        "id": "179",
        "home_address": "Optiquall  Pune Maharashtra India",
        "user_login": "mukti.thakor@optiquall.com",
        "first_name": "mukti",
        "last_name": "thakor",
        "email": "mukti.thakor@optiquall.com",
        "phone_number": "",
        "timezone": "Asia/Calcutta",
        "is_google_authenticated": "1",
        "is_facebook_authenticated": "1",
        "image_url": "",
        "active_trip_id": "0",
        "journey_type": "",
        "trip_identifier": "",
        "trip_author": "",
        "token_info": {
            "access_token": "e692f28b8ffe16e683540e7b2d42286a47cbe7fb",
            "expires_in": "3600",
            "token_type": "Bearer",
            "scope": null,
            "refresh_token": "8512b001e35eb69c7d3b45e20138bf91b210bafb"
        }
    },
    "notification_count": 0
}

我的代碼

let decoder = JSONDecoder()
        //decoder.keyDecodingStrategy = .convertFromSnakeCase
        do{

            let succeResponse = try decoder.decode(successResponse.self, from: data!)
            print(succeResponse.data)

        } catch let error as Error{

            print(error.localizedDescription)
        }

struct SuccessResponse: Codable {

    var status:Int?
    var message:String?
    var errorMessage:[Int]? = []
    //var developerMessage:String?
    var notificationCount:Int?
    var data:data

    private enum CodingKeys : String, CodingKey {
        case status = "status", message = "message", notificationCount = "notification_count", errorMessage = "error_message", data = "data"
    }

}

struct Data: Codable {

    var id:Int?
    var homeAddress:String?
    var userLogin:String?
    var firstName:String?
    var lastName:String?
    var email:String?
    var phoneNumber:String?
    var timezone:String?

    var isGoogleAuthenticated:String?
    var isFacebookAuthenticated:String?
    var imageUrl:String?
    var activeTripId:String?
    var journeyType:String?
    var tripIdentifier:String?
    var tripAuthor:String?

    var tokenInfo:tokenInfo


    private enum CodingKeys : String, CodingKey {
        case id = "id", homeAddress = "home_address", userLogin = "user_login", firstName = "first_name", lastName = "last_name", email = "email", phoneNumber = "phone_number", timezone = "timezone", isGoogleAuthenticated = "is_google_authenticated",isFacebookAuthenticated = "is_facebook_authenticated", imageUrl = "image_url", activeTripId = "active_trip_id", journeyType = "journey_type", tripIdentifier = "trip_identifier" , tripAuthor = "trip_author", tokenInfo = "token_info"
    }

}


struct TokenInfo: Codable {

    var accessToken:String?
    var expiresIn:String?
    var tokenType:String?
    var scope:Bool?
    var refreshToken:String?

    private enum CodingKeys : String, CodingKey {
        case accessToken = "access_token", expiresIn = "expires_in", tokenType = "token_type", scope = "scope", refreshToken = "refresh_token"
    }
}

代替

var id:Int?

var id:String?

首先,正如評論中提到的,在DecodingError捕獲塊中永遠不要print(error.localizedDescription) 始終print(error)以獲取此全面的錯誤消息:

typeMismatch(Swift.Int, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "id", intValue: nil)], debugDescription: "預期解碼 Int 但找到了一個字符串/數據。”,underlyingError: nil))

它告訴您結構data中的鍵id值( [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "id", intValue: nil)] )是一個字符串(找到一個字符串/ data ) 而不是預期解碼Int

因此,按照 Sh_Khan 的回答中的建議,將id聲明為String


這是一個能夠解碼成功和失敗案例的解決方案。

根據status的值,根對象被解碼為具有關聯值的枚舉。

其他變化:

  • 這些結構體被命名為ResponseUserData
  • 所有 struct 成員(除了scope )都被聲明為非可選的。 如果您收到錯誤消息,請僅將受影響的類型更改為可選項。
  • 所有 struct 成員都聲明為常量 ( let )。
  • 為了擺脫大部分 CodingKeys,添加了convertFromSnakeCase策略

結構:

enum Response : Decodable {

    case success(Int, Int, String, UserData)
    case failure(Int, Int, String, [String:String])

    private enum CodingKeys : String, CodingKey {
        case status = "status", message = "message", notificationCount = "notificationCount", errorMessage = "errorMessage", data = "data"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let status = try container.decode(Int.self, forKey: .status)
        let notificationCount = try container.decode(Int.self, forKey: .notificationCount)
        let message = try container.decode(String.self, forKey: .message)
        if status == 200 {
            let userData = try container.decode(UserData.self, forKey: .data)
            self = .success(status, notificationCount, message, userData)
        } else {
            let errorMessage = try container.decode([String:String].self, forKey: .errorMessage)
            self = .failure(status, notificationCount, message, errorMessage)
        }
    }
}

struct UserData : Decodable {

    let id, homeAddress, userLogin, firstName, lastName, email, phoneNumber, timezone : String
    let isGoogleAuthenticated, isFacebookAuthenticated, imageUrl, activeTripId, journeyType, tripIdentifier, tripAuthor : String
    let tokenInfo : TokenInfo
}

struct TokenInfo : Decodable {
    let accessToken, expiresIn, tokenType, refreshToken : String
    let scope : String?
}

用法:

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
   let response = try decoder.decode(Response.self, from: data!)
   switch response {
    case let .success(status, notificationCount, message, userData): print(status, notificationCount, message, userData)
    case let .failure(status, notificationCount, message, errorMessage): print(status, notificationCount, message, errorMessage) 
   } 

} catch {
    print(error)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM