Fail to use Protocol contains Protocol adopting Codable

泄露秘密 提交于 2020-02-04 05:48:05

问题


Consider the followings:

protocol A: Codable {
  var b: B { get }
  var num: Int { get }
}
protocol B: Codable {
  var text: String { get }
}
struct C: A {
  var b: B
  var num: Int
}

The compiler gives two errors

  • Type 'C' does not conform to protocol 'Decodable'
  • Type 'C' does not conform to protocol 'Encodable'

However Both A and B are Codable. How to solve/avoid these errors?

Reference:

EDITED

As the auto-synthesis for Codable not working, I manually implemented the required methods.

struct C: A {
  var b: B
  var num: Int

  enum CodingKeys: String, CodingKey {
    case b
    case num
  }

  func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(num, forKey: .num)
    try container.encode(b, forKey: .b)
  }
  init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    num = try values.decode(Int.self, forKey: .num)
    b = try values.decode(B.self, forKey: .b)
  }
}

and now it gives new errors


回答1:


A protocol doesn't tell the compiler how to encode/decode classes/structs that conforms to it. You need an implementation of the protocol for the compiler to fully understand how to init an instance of the C struct.

struct D: B {
  var text: String
}

struct C: A {
  var b: B
  var num: Int

  public init(from decoder: Decoder) throws {
    b = D(text: " ")
    num = 0
  }

  public func encode(to encoder: Encoder) throws {

  } 
}

Here is a more complete example in line with the second part of the question.

protocol A: Codable {
  var b: B { get }
  var num: Int { get }
}
protocol B: Codable {
  var text: String { get }
}
struct D: B {
  var text: String
}

struct C: A {
  var b: B
  var num: Int

  enum CodingKeys: String, CodingKey {
    case b
    case num
  }

  public init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    num = try values.decode(Int.self, forKey: .num)
    let text = try values.decode(String.self, forKey: .b)
    b = D(text: text)
  }

  public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(num, forKey: .num)
    try container.encode(b.text, forKey: .b)
  }
}



回答2:


You should implement init(from decoder: Decoder) and encode(to encoder: Encoder) in struct C because these are required for Codable (Decodable & Encodable) protocol use.

public init(from decoder: Decoder) throws{

}

public func encode(to encoder: Encoder) throws{

} 

EDITED

In Swift protocol does not confirms to themselves so you should use associatedtype in Protocol A which confirms to Protocol B.

for better understanding of Protocol please read this answer.

https://stackoverflow.com/a/43408193/6303078

protocol B: Codable {
    var text: String { get }
}

protocol A: Codable {
    associatedtype CodableType : B
    var b: CodableType { get }
    var num: Int { get }
}

struct D: B {
    var text: String
}

struct C<ElementType:B> : A{

    typealias CodableType = ElementType

    var b: CodableType
    var num: Int

    enum CodingKeys: String, CodingKey {
        case b
        case num
    }

    public init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        num = try values.decode(Int.self, forKey: .num)
        b = try values.decode(CodableType.self, forKey: .b)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(num, forKey: .num)
        try container.encode(b, forKey: .b)
    }
}


来源:https://stackoverflow.com/questions/49147559/fail-to-use-protocol-contains-protocol-adopting-codable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!