使用可编码协议解析JSON

时间:2019-07-17 13:21:49

标签: swift

由于数据格式不正确,因此无法读取。尝试解析下面给出的JSON。将数据对象也包含在struct中时抛出错误

我的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"
    }
}

2 个答案:

答案 0 :(得分:2)

替换

var id:Int?

使用

var id:String?

答案 1 :(得分:1)

首先,如DecodingError catch块中的注释从不print(error)所述。始终id以获得此综合错误消息:

  

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)] )是一个字符串(找到了一个字符串 /数据),而不是预期用于解码 Int

因此,按照Sh_Khan的回答中的建议,将String声明为status


这是一种能够解码成功案例和失败案例的解决方案。

根对象根据Response中的值被解码为具有相关值的枚举。

其他更改:

  • 这些结构分别命名为UserDatascope
  • 所有结构成员(let除外)都声明为非可选。如果收到错误消息,则仅将受影响的类型更改为可选类型。
  • 所有结构成员都声明为常量(convertFromSnakeCase)。
  • 为摆脱大多数CodingKey,添加了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)
}

用法:

ProgrammingError: No results