Создание объекта Codable с объектами Codable любого типа?

Я хочу создать класс, в котором будет храниться Date и любой объект, соответствующий протоколу Codable. Я хотел бы, чтобы этот класс также соответствовал самому протоколу Codable.

Я могу сделать это для одного объекта следующим образом:

class CodableContainerA: NSObject, Codable {
    var date: Date?
    var item: CodableTypeA?
}

Я бы предпочел не создавать отдельный CodableContainerX для каждого CodableTypeX, который у меня есть.

Мой текущий обходной путь состоит в том, чтобы создать класс с именем CodableBaseClass, который соответствует Codable, вывести из него каждый CodableType и определить мой класс следующим образом:

class CodableContainer: NSObject, Codable {
    var date: Date?
    var item: CodableBaseClass?
}

Это кажется долгим путем и похоже на то, что я должен сделать, заставив CodableType соответствовать протоколу, но я не уверен, как это сделать. Если я определяю item как тип Codable? или (Any & Codable)?, я получаю сообщение об ошибке

Type 'CodableContainer' does not conform to protocol 'Decodable'

Я использую Свифт 4.

Любая помощь или совет будут приняты с благодарностью. Большое спасибо,


person Josh Paradroid    schedule 05.01.2018    source источник


Ответы (2)


Вот для чего нужны общие классы:

class CodableContainer<T: Codable>: NSObject, Codable {
    var date: Date?
    var item: T?
}
person Code Different    schedule 05.01.2018

Всякий раз, когда вы задаетесь вопросом об отдельном классе для каждого базового типа, подумайте "универсальные". Например.

struct CodableContainer<T: Codable>: Codable { 
    let date: Date
    let item: T
}
  • Я бы использовал struct, если только вам не понадобился class по какой-то конкретной причине.
  • Я бы сделал свойства неизменяемыми, если по какой-то причине они вам не нужны.
  • Я бы не стал подклассом NSObject, если бы не было какой-то конкретной причины, по которой этот конкретный контейнер должен был быть подклассом NSObject.
  • Я бы сделал свойства необязательными, если только вам не нужно, чтобы они были необязательными.

Но отредактируйте это, как считаете нужным. Ключевым моментом является общий шаблон.


Вам может понадобиться функция декодирования, которая декодирует с использованием некоторого согласованного DateDecodingStrategy, например.

extension CodableContainer {
    static func decodeJSON(_ data: Data) throws -> CodableContainer {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        return try decoder.decode(self, from: data)
    }
}

Очевидно, используйте любые dateDecodingStrategy, какие хотите. Но тогда вы можете декодировать с помощью:

let result = try CodableContainer<Foo>.decodeJSON(data)
person Rob    schedule 05.01.2018
comment
Я отметил ответ Code Different как принятый ответ, поскольку он был первым и более кратким, но я действительно ценю ваш ответ и предложения и включил их в свой код. Это все вещи, о которых я задавался вопросом сегодня, но я решил, что заставлю это работать, прежде чем я заставлю его работать хорошо. Надеюсь, мой код теперь оба! Большое спасибо. - person Josh Paradroid; 05.01.2018