使用类继承是否会破坏类的可解码性。例如下面的代码

class Server : Codable {
    var id : Int?
}

class Development : Server {
    var name : String?
    var userId : Int?
}

var json = "{\"id\" : 1,\"name\" : \"Large Building Development\"}"
let jsonDecoder = JSONDecoder()
let item = try jsonDecoder.decode(Development.self, from:json.data(using: .utf8)!) as Development

print(item.id ?? "id is nil")
print(item.name ?? "name is nil") here


输出为:

1
name is nil


现在,如果我将其反转,则名称会解码,而id不会。

class Server {
    var id : Int?
}

class Development : Server, Codable {
    var name : String?
    var userId : Int?
}

var json = "{\"id\" : 1,\"name\" : \"Large Building Development\"}"
let jsonDecoder = JSONDecoder()
let item = try jsonDecoder.decode(Development.self, from:json.data(using: .utf8)!) as Development

print(item.id ?? "id is nil")
print(item.name ?? "name is nil")


输出为:

id is nil
Large Building Development


而且您不能在两个类中都表示Codable。

最佳答案

我相信在继承的情况下,您必须自己实现Coding。即,必须在父类和子类中都指定CodingKeys并实现init(from:)encode(to:)。根据WWDC video(大约49:28,如下图所示),必须使用超级编码器/解码器调用超级。

swift - 在带有继承的Swift 4中使用Decodable-LMLPHP

required init(from decoder: Decoder) throws {

  // Get our container for this subclass' coding keys
  let container = try decoder.container(keyedBy: CodingKeys.self)
  myVar = try container.decode(MyType.self, forKey: .myVar)
  // otherVar = ...

  // Get superDecoder for superclass and call super.init(from:) with it
  let superDecoder = try container.superDecoder()
  try super.init(from: superDecoder)

}


该视频似乎没有停止显示编码方面(但在container.superEncoder()方面是encode(to:)),但是在encode(to:)实现中其工作方式几乎相同。我可以在这种简单的情况下确认这项工作(请参见下面的操场代码)。

我仍然要通过从NSCoding转换的更复杂的模型来解决某些奇怪的行为,该模型具有许多新嵌套的类型(包括structenum),这些类型都表现出了这种意外的nil行为和“不应该”。请注意,可能存在涉及嵌套类型的边缘情况。

编辑:嵌套类型似乎在我的测试环境中工作正常;我现在怀疑自引用类(认为是树节点的子代)有一些问题,而自引用类本身也包含该类的各种子类的实例。一个简单的自引用类的测试可以很好地解码(即没有子类),因此我现在将精力集中在子类案例失败的原因上。

更新时间:17年6月25日:我最终向苹果提交了一个与此有关的错误。 rdar:// 32911973-不幸的是,包含Superclass元素的Subclass: Superclass数组的编码/解码周期将导致该数组中的所有元素都被解码为Superclass(子类的init(from:)从未被调用,导致数据丢失或更糟)。

//: Fully-Implemented Inheritance

class FullSuper: Codable {

    var id: UUID?

    init() {}

    private enum CodingKeys: String, CodingKey { case id }

    required init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(UUID.self, forKey: .id)

    }

    func encode(to encoder: Encoder) throws {

        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)

    }

}

class FullSub: FullSuper {

    var string: String?
    private enum CodingKeys: String, CodingKey { case string }

    override init() { super.init() }

    required init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)
        let superdecoder = try container.superDecoder()
        try super.init(from: superdecoder)

        string = try container.decode(String.self, forKey: .string)

    }

    override func encode(to encoder: Encoder) throws {

        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(string, forKey: .string)

        let superencoder = container.superEncoder()
        try super.encode(to: superencoder)

    }
}

let fullSub = FullSub()
fullSub.id = UUID()
fullSub.string = "FullSub"

let fullEncoder = PropertyListEncoder()
let fullData = try fullEncoder.encode(fullSub)

let fullDecoder = PropertyListDecoder()
let fullSubDecoded: FullSub = try fullDecoder.decode(FullSub.self, from: fullData)


上级和子类属性都在fullSubDecoded中恢复。

关于swift - 在带有继承的Swift 4中使用Decodable,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53315685/

10-11 22:14