Выход:

аюсь найти лучший способ кодировать / декодировать массив структур, соответствующих быстрому протоколу, используя новый JSONDecoder / Encoder в Swift 4.

Я составил небольшой пример, чтобы проиллюстрировать проблему:

Сначала у нас есть тег протокола и несколько типов, которые соответствуют этому протоколу.

protocol Tag: Codable {
    var type: String { get }
    var value: String { get }
}

struct AuthorTag: Tag {
    let type = "author"
    let value: String
}

struct GenreTag: Tag {
    let type = "genre"
    let value: String
}

Затем у нас есть Тип статьи, который имеет массив тегов.

struct Article: Codable {
    let tags: [Tag]
    let title: String
}

Наконец, мы кодируем или декодируем статью

let article = Article(tags: [AuthorTag(value: "Author Tag Value"), GenreTag(value:"Genre Tag Value")], title: "Article Title")


let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(article)
let jsonString = String(data: jsonData, encoding: .utf8)

И это структура JSON, которая мне нравится иметь.

{
 "title": "Article Title",
 "tags": [
     {
       "type": "author",
       "value": "Author Tag Value"
     },
     {
       "type": "genre",
       "value": "Genre Tag Value"
     }
 ]
}

Проблема в том, что в какой-то момент мне нужно включить свойство типа для декодирования массива, но для декодирования массива я должен знать его тип.

РЕДАКТИРОВАТЬ:

Мне понятно, почему Decodable не может работать из коробки, но, по крайней мере, Encodable должен работать. Следующая измененная структура Article компилируется, но вылетает со следующим сообщением об ошибке.

fatal error: Array<Tag> does not conform to Encodable because Tag does not conform to Encodable.: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-900.0.43/src/swift/stdlib/public/core/Codable.swift, line 3280

struct Article: Encodable {
    let tags: [Tag]
    let title: String

    enum CodingKeys: String, CodingKey {
        case tags
        case title
    }

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

let article = Article(tags: [AuthorTag(value: "Author Tag"), GenreTag(value:"A Genre Tag")], title: "A Title")

let jsonEncoder = JSONEncoder()
let jsonData = try jsonEncoder.encode(article)
let jsonString = String(data: jsonData, encoding: .utf8)

И это соответствующая часть из Codeable.swift

guard Element.self is Encodable.Type else {
    preconditionFailure("\(type(of: self)) does not conform to Encodable because \(Element.self) does not conform to Encodable.")
}

Источник:https://github.com/apple/swift/blob/master/stdlib/public/core/Codable.swift

Ответы на вопрос(4)

Ваш ответ на вопрос