首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用可选字段解码json

用可选字段解码json
EN

Stack Overflow用户
提问于 2022-06-10 11:05:12
回答 2查看 196关注 0票数 0

我正在尝试解析一个json字符串,其中一些键没有固定。有些键与错误相关,可能是错误,也可能是结果数据。以下是两个例子:

代码语言:javascript
复制
{
    "ok": true,
    "result": {
        "code": "694kyH",
        "short_link": "shrtco.de\/694kyH",
        "full_short_link": "https:\/\/shrtco.de\/694kyH",
        "short_link2": "9qr.de\/694kyH",
        "full_short_link2": "https:\/\/9qr.de\/694kyH",
        "short_link3": "shiny.link\/694kyH",
        "full_short_link3": "https:\/\/shiny.link\/694kyH",
        "share_link": "shrtco.de\/share\/694kyH",
        "full_share_link": "https:\/\/shrtco.de\/share\/694kyH",
        "original_link": "http:\/\/google.com"
    }
}

{
    "ok": false,
    "error_code": 2,
    "error": "This is not a valid URL, for more infos see shrtco.de\/docs"
}

我将如何解析这个JSON。我试着像下面这样构建我的班级,但是它不起作用:

代码语言:javascript
复制
struct ShortLinkData: Codable {
    let ok: Bool
    let result: Result?
    let errorCode: Int?
    let error: String?
    
    private enum CodingKeys : String, CodingKey { case ok, result, errorCode = "error_code", error }

       init(from decoder: Decoder) throws {
          let container = try decoder.container(keyedBy: CodingKeys.self)
          ok = try container.decode(Bool.self, forKey: .ok)
           result = try container.decode(Result.self, forKey: .result)
           errorCode = try container.decodeIfPresent(Int.self, forKey: .errorCode)
           error = try container.decodeIfPresent(String.self, forKey: .error)
      }
}

// MARK: - Result
struct Result: Codable {
    let code, shortLink: String
    let fullShortLink: String
    let shortLink2: String
    let fullShortLink2: String
    let shortLink3: String
    let fullShortLink3: String
    let shareLink: String
    let fullShareLink: String
    let originalLink: String

    enum CodingKeys: String, CodingKey {
        case code
        case shortLink = "short_link"
        case fullShortLink = "full_short_link"
        case shortLink2 = "short_link2"
        case fullShortLink2 = "full_short_link2"
        case shortLink3 = "short_link3"
        case fullShortLink3 = "full_short_link3"
        case shareLink = "share_link"
        case fullShareLink = "full_share_link"
        case originalLink = "original_link"
    }
    init(from decoder: Decoder) throws {
       let container = try decoder.container(keyedBy: CodingKeys.self)
        code = try container.decode(String.self, forKey: .code)
        shortLink = try container.decode(String.self, forKey: .shortLink)
        fullShortLink = try container.decode(String.self, forKey: .fullShortLink)
        shortLink2 = try container.decode(String.self, forKey: .shortLink2)
        fullShortLink2 = try container.decode(String.self, forKey: .fullShortLink2)
        shortLink3 = try container.decode(String.self, forKey: .shortLink3)
        fullShortLink3 = try container.decode(String.self, forKey: .fullShortLink3)
        shareLink = try container.decode(String.self, forKey: .shareLink)
        fullShareLink = try container.decode(String.self, forKey: .fullShareLink)
        originalLink = try container.decode(String.self, forKey: .originalLink)
   }
}

我的解析代码:

代码语言:javascript
复制
let str = String(decoding: data, as: UTF8.self)
print(str)
let shortURL = try? JSONDecoder().decode(ShortLinkData.self, from: data)
return shortURL!

我总是在shortURL对象中获得零。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-06-10 13:16:01

您应该将其分成几个步骤,以避免在模型中处理所有这些选项。

首先,创建一个结构,该结构只具有保证存在的属性。在您的案例中,ok

代码语言:javascript
复制
struct OKResult: Codable{
    let ok: Bool
}

然后为错误状态创建一个,为成功状态创建一个:

代码语言:javascript
复制
struct ErrorResult: Codable{
    let ok: Bool
    let errorCode: Int
    let error: String
    
    private enum CodingKeys: String, CodingKey{
        case ok, errorCode = "error_code", error
    }
}

struct ShortLinkData: Codable {
    let ok: Bool
    let result: Result
}

struct Result: Codable {
    let code, shortLink: String
    let fullShortLink: String
    let shortLink2: String
    let fullShortLink2: String
    let shortLink3: String
    let fullShortLink3: String
    let shareLink: String
    let fullShareLink: String
    let originalLink: String

    enum CodingKeys: String, CodingKey {
        case code
        case shortLink = "short_link"
        case fullShortLink = "full_short_link"
        case shortLink2 = "short_link2"
        case fullShortLink2 = "full_short_link2"
        case shortLink3 = "short_link3"
        case fullShortLink3 = "full_short_link3"
        case shareLink = "share_link"
        case fullShareLink = "full_share_link"
        case originalLink = "original_link"
    }
}

然后,您可以解码数据:

代码语言:javascript
复制
guard try JSONDecoder().decode(OKResult.self, from: data).ok else{
    let errorResponse = try JSONDecoder().decode(ErrorResult.self, from: data)
    //handle error scenario
    fatalError(errorResponse.error) // or throw custom error or return nil etc...
}

let shortlinkData = try JSONDecoder().decode(ShortLinkData.self, from: data)

备注:

necessary.

  • Never
  • 您的init不使用try?,这将向
  • 隐藏所有错误,您需要将其封装在do catch块中或使函数throwing,并在树上处理更多的错误。
票数 1
EN

Stack Overflow用户

发布于 2022-06-10 15:00:27

实际上没有可选的字段。服务器发送两个不同但不同的JSON字符串。

解码这两个JSON字符串的一种合适方法是带有关联值的枚举。它解码ok密钥,然后解码result字典或errorCodeerror

代码语言:javascript
复制
enum Response : Decodable {
    case success(ShortLinkData), failure(Int, String)
    
    private enum CodingKeys : String, CodingKey { case ok, result, errorCode, error }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let ok = try container.decode(Bool.self, forKey: .ok)
        if ok {
            let result = try container.decode(ShortLinkData.self, forKey: .result)
            self = .success(result)
        } else {
            let errorCode = try container.decode(Int.self, forKey: .errorCode)
            let error = try container.decode(String.self, forKey: .error)
            self = .failure(errorCode, error)
        }
    }
}

ShortLinkData中,如果指定convertFromSnakeCase密钥解码策略,则convertFromSnakeCase方法和CodingKeys是冗余的。

代码语言:javascript
复制
struct ShortLinkData: Decodable {
    let code, shortLink: String
    let fullShortLink: String
    let shortLink2, fullShortLink2: String
    let shortLink3, fullShortLink3: String
    let shareLink, fullShareLink: String
    let originalLink: String
}


do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let result = try decoder.decode(Response.self, from: data)
    switch result {
        case .success(let linkData): print(linkData)
        case .failure(let code, let message): print("An error occurred with code \(code) and message \(message)")
    }
} catch {
    print(error)
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72573272

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档