美文网首页
【iOS开发】使用Codable时要注意的问题

【iOS开发】使用Codable时要注意的问题

作者: Lebron_James | 来源:发表于2019-05-08 08:47 被阅读0次

    在Swift 4推出Codable之后,我们基本上可以抛弃字典转模型的第三方库了。在我自己的使用过程中,发现了一些会导致无法解码JSON的细节问题。在此跟大家分享下。

    一、类型的某个属性有默认值,后台返回的JSON没有这个属性对应的数据

    正常的Demo

    User

    假设我们有一个User类型,有一个id属性,和一个是否被当前用户关注的属性isFollowedByCurrentUser,并实现了Codable协议,代码如下:

    struct User: Codable {
        var id: String
        var isFollowedByCurrentUser: Bool?
    
        enum CodingKeys: String, CodingKey {
            case id
            case isFollowedByCurrentUser = "followed"
        }
    }
    
    解码

    我们的JSON数据如下:

    let jsonString = """
      {
        "id":"efa41bae-25fa-428b-99c1-6d3c1b178875",
        "followed": true
      }
    """
    

    JSONDecoder进行解码:

    let decoder = JSONDecoder()
    
    let data = jsonString.data(using: .utf8)!
    
    do {
        let user = try decoder.decode(User.self, from: data)
        print(user)
    } catch {
        print("error: \(error)")
    }
    

    毫无疑问,上面的代码是可以解码成功的。

    失败的Demo

    有些时候,后台返回的JSON数据可能缺少某些字段,假设缺少了followed,那么现在的JSON数据为:

    let jsonString = """
      {
        "id":"efa41bae-25fa-428b-99c1-6d3c1b178875"
      }
    """
    

    这时我们用上面的JSONDecoder进行解码,也是可以解码成功的,只不过isFollowedByCurrentUser的值为nil而已。

    现在问题来了,我们看回User类型。通常我们在某个类型添加一个Bool属性时,一般会给他一个默认值false,所以我们会习惯的把User写成:

    struct User: Codable {
    
        var id: String
        var isFollowedByCurrentUser = false
    
        enum CodingKeys: String, CodingKey {
            case id
            case isFollowedByCurrentUser = "followed"
        }
    }
    

    这时如果我们再用JSONDecoder把缺少followed字段的JSON数据转成User的话,是无法转成功的,错误如下:

    error: keyNotFound(CodingKeys(stringValue: "followed", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"followed\", intValue: nil) (\"followed\").", underlyingError: nil))
    

    JSONDecoder在JSON数据中无法找到followed对应的值。

    解决办法

    我们无法保证服务器总是返回完整的数据,所以只能从我们客户端去解决问题。

    1. 把类型的所有属性都定义为Optional类型

    这是最简单方便的方法。这样解码的时候,JSONDecoder发现JSON没有对应的数据,就自动把这个属性设置为nil

    2. 实现Decodable的初始化函数,并使用decodeIfPresent来解码

    正常情况下,我们定义了CodingKeys之后,不需要手动实现init(from decoder: Decoder) throws这个初始化函数的,JSONDecoder就可以正常解码。但是我们把isFollowedByCurrentUser定义成一个非可选类型,我们必须实现这个初始化函数,才能正常解码:

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        isFollowedByCurrentUser = try container.decodeIfPresent(Bool.self, forKey: .isFollowedByCurrentUser) ?? false
    }
    

    欢迎加入我管理的Swift开发群:536353151

    相关文章

      网友评论

          本文标题:【iOS开发】使用Codable时要注意的问题

          本文链接:https://www.haomeiwen.com/subject/kpsjoqtx.html