【问题标题】:Optional value in Codable is nilCodable 中的可选值为 nil
【发布时间】:2020-09-16 10:10:52
【问题描述】:

我的 Swift 5 (Xcode 11.5) 应用程序将人员保存在文本文件(json 格式)中。

我用来解码json文本的structs:

struct People:Codable {
    var groupName:String
    var groupLocation:String 
    var members:[Person]

    init(_ gn:String,_ gl:String,_ m:[Person] {
        groupName = gn
        groupLocation = gl
        members = m
}

struct Person:Codable {
    var name:String
    var age:Int
    var profession:String?

    init(_ n:String,_ a:Int,_ p:String?) {
        name = n
        age = a
        profession = (p==nil) ? "none" : p!
    }
}

解码文本文件的内容:

let jsonData = Data(text.utf8)
let decoder = JSONDecoder()
let people = try decoder.decode(People.self, from: jsonData)
let members = people.members

for (i,member) in members.enumerated() {
    //print(member.profession==nil)
    //Do stuff
}

profession 是稍后添加的,将来可能还会添加更多值,但我希望我的应用程序能够向后兼容旧文件。如果profession 不存在,它应该使用"none" 代替(参见上面的代码)但是当我在解码后检查member.profession 时,它仍然是nilname, age,... 都包含正确的值,因此该部分有效。

如果 json 文件中不存在 profession 的值,我该如何在 struct 中赋值?什么是最简单/最干净的方法,所以我也可以稍后添加,如有必要(例如生日,性别,...)?

【问题讨论】:

  • 覆盖init(decoder:),并检查decodeifPresent()
  • 这能回答你的问题吗? Swift Codable Decode Manually Optional Variable
  • 为什么要用字符串"none"来表示不存在的职业? nil 就是为此而生的!
  • @Sweeper 这只是一个例子。我需要 String 有一个值 !=nil ,然后在我的应用程序中显示而无需进一步检查。
  • @Larme 我在发布这个问题之前看到了这个问题,但老实说,我不知道它是如何工作的,因为我不仅不使用枚举,而且我上面发布的两个代码段也在 2单独的 swift 文件。另外,我不只是想检查 json 文件中是否存在 profession,如果不存在,我还想给它一个自定义值。

标签: json swift codable


【解决方案1】:

如果您需要以不同于Codable 的方式解析您的 JSON,则需要实现 自定义初始化程序 init(from:),即

struct Person:Codable {
    var name:String
    var age:Int
    var profession: String
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decode(String.self, forKey: .name)
        self.age = try container.decode(Int.self, forKey: .age)
        if let profession = try container.decodeIfPresent(String.self, forKey: .profession) {
            self.profession = profession
        } else {
            self.profession = "none"
        }
    }
}

另外,由于您总是为profession 赋值,因此无需设置为optional

【讨论】:

  • Larme 用这段代码链接了一个 pastebin,唯一的区别是他在里面添加了 extension Personinit。我首先尝试不使用它并将新的init 放入原始结构中,但是当我想再次将更改保存在文件中时,Xcode 给了我一个错误,使用相同的Person:Extra arguments at positions #1, #2, #3 in call
  • 没关系,如果它在结构中但也需要创建用于编码另一个 init 的对象(我在上面发布但没有optional 的代码),这确实有效。 self(对于nameage)真的有必要吗?没有它也能正常工作。
  • self 与属性一起使用只是一种遵循的编码风格。你可以不用它写任何你喜欢的东西。
  • 我明白了。我知道你确实需要self 来代替profession,所以它会使用正确的。
猜你喜欢
  • 1970-01-01
  • 2018-03-30
  • 2018-11-30
  • 1970-01-01
  • 1970-01-01
  • 2019-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多