DateDemo
соответствует Decodable
, но явно не определяет init(from:Decoder) throws
.Таким образом, Swift синтезирует определение init(from:Decoder) throws
, которое декодирует свойства DateDemo
.
DateDemo2
наследуется от DateDemo
.Он добавляет одно свойство: eventsDateTimes3
.Он не определяет никаких инициализаторов.Обычно Swift жаловался на отсутствие инициализаторов.Однако, поскольку новое свойство является одновременно var
и необязательным, Swift считает, что оно имеет значение по умолчанию nil
.
Поскольку единственное новое свойство DateDemo2
имеет значение по умолчанию, Swift применяется автоматическое наследование инициализатора .Ваш класс DateDemo2
наследует все инициализаторы, назначенные его суперклассом.Унаследован только один инициализатор: синтезированный Decodable
инициализатор.Унаследованный инициализатор инициализирует eventsDateTimes3
его значением по умолчанию (nil
).Именно так работают наследуемые инициализаторы.
Вы надеялись, что Swift синтезирует Decodable
инициализатор для DateDemo2
, как это было для DateDemo
, путем инициализации eventsDateTimes3
из Decoder
.Но Свифт не делает этого.Вот что сказал Итай Фербер (программист Apple, ответственный за реализацию Coding
) на форуме Swift :
Этот случай был бы улучшен, если бы компилятор мог синтезировать SuperClass.init(from:)
вместо наследования, но он не сможет обойтись без рефакторинга системы соответствия и наследования протоколов Swift (и без синтаксиса для устранения неоднозначности между «я не предоставляю реализацию, потому что я хотел бы наследовать» и «я»).я не предоставляю реализацию, потому что я хотел бы синтезировать ")
Другими словами, есть два законных случая:
- Вы хотите, чтобы ваш подкласс наследовал свой суперклассinitializer и default-initialize новые свойства.
- Вы хотите, чтобы компилятор синтезировал инициализатор, который декодирует новые свойства.
Вы всегда получаете # 1 сейчас, потому что это все, что былодо того, как была добавлена система Codable
, и потому что нет синтаксиса для сообщения компилятору, что вы хотите # 2.
Так что вам нужно внедрить init(from:)
самостоятельно в DateDemo2
.Вот реализация:
class DateDemo2 : DateDemo {
var eventsDateTimes3 : [Date]?
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
eventsDateTimes3 = try container.decode([Date]?.self, forKey: .eventsDateTimes3)
try super.init(from: decoder)
}
private enum CodingKeys: String, CodingKey {
case eventsDateTimes3
}
}