Общий Decodable перестал работать с Swift 4.1 - PullRequest
0 голосов
/ 29 апреля 2018

Итак, у нас есть два типа ответов JSON в нашем API:

{
  "data": { } // some object in here
  "meta": { } // an object in here
}

и

{
  "data": [ ] // array of objects
  "meta": { } // an object in here
}

Для их декодирования мы используем JSONDecoder () и следующую общую структуру ответа:

public struct Response<T: Codable>: Codable {
    public let data: T
    public let meta: Meta?
}

Это прекрасно работает с Swift 4.0, используя .map(Response<[MyObject]>.self) или .map(Response<MySingleObject>.self)

, но по какой-то причине это больше не работает со Swift 4.1 и Xcode 9.3. Похоже, он вообще не отображает «данные» и поэтому считает, что список [MyObject] находится на первом уровне.

dataCorrupted: Swift.DecodingError.Context
      ▿ codingPath: 3 elements
        - CodingKeys(stringValue: "data", intValue: nil)
        ▿ _JSONKey(stringValue: "Index 0", intValue: 0)
          - stringValue: "Index 0"
          ▿ intValue: Optional(0)
            - some: 0
        - CodingKeys(stringValue: "creationDate", intValue: nil)
      - debugDescription: "Date string does not match format expected by formatter."

Обратите внимание, что "creationDate" является свойством MyObject. Формат даты определенно правильный (установлен на .formatted(customFormatter) в декодере), так как он работает с Swift 4.0 в Xcode 9.2

Как мы можем продолжать вести себя так же со Swift 4.1? Цель здесь состояла в том, чтобы не создавать типизированный тип Response для каждого ответа API, а использовать вместо него универсальный тип, потому что единственное различие заключается в типе объекта ответа и в том, что иногда он возвращает список, а иногда один объект под data. * 1024. *

Также связано: есть ли способ обеспечить, что если мы используем Response<[MyObject]>.self, то MyObject также должно соответствовать Codable?

Заранее спасибо.

Edit:

Код ниже отображается правильно в Xcode 9.2 и Swift 4, но не отображается (создает ноль) в Xcode 9.3 и Swift 4.1

public struct MyObject: Codable {
    public let creationDate: Date

    enum CodingKeys: String, CodingKey {
        case creationDate = "creation_date"
    }
}


public struct Response<T: Codable>: Codable {
    public let data: T
    public let meta: Meta?
}


public struct Meta: Codable {
    public let count: Int?
}


let formatter = DateFormatter()
formatter.dateFormat = "yyyy-mm-dd HH:mm:ss"

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)

let jsonDataSingle: Data = """
    {
        "data": { "creation_date": "2018-04-29 18:00:11" },
        "meta": null
    }
""".data(using: .utf8)!

let jsonDataList: Data = """
    {
        "data": [{ "creation_date": "2018-04-10 17:00:11" }, { "creation_date": "2018-04-29 18:00:11" }],
        "meta": null
    }
""".data(using: .utf8)!

let singleObject = try? decoder.decode(Response<MyObject>.self, from: jsonDataSingle)
dump(singleObject)
let listOfObjects = try? decoder.decode(Response<[MyObject]>.self, from: jsonDataList)
dump(listOfObjects)

1 Ответ

0 голосов
/ 29 апреля 2018

Я не получаю никаких ошибок. Пожалуйста, отправьте это. В качестве упражнения я добавил соответствие CustomStringConvertible и заменил дамп на печать.

extension Response: CustomStringConvertible {
  public var description: String {
    return "data = \(data) | meta = \(meta)"
  }
}

extension MyObject: CustomStringConvertible {
  public var description: String {
    return "date = \(creationDate)"
  }
}

Я использую Xcode 9.3, Swift 4.1 версии 9E145, выпущенную через App Store.

enter image description here

...