Как использовать init (из декодера :) при чтении связанных JSON данных - PullRequest
0 голосов
/ 03 мая 2020

У меня есть словарный массив JSON, и мне нужно декодировать его для создания типа данных (Hitter), объект Hitter должен содержать необработанные данные JSON, и мне нужно добавлять свойства в Hitter на протяжении всей жизни. из приложения. Я обнаружил, что мне нужно использовать init (из декодера :), но как правильно вызвать init? Я буду хранить Hitter в структуре League.

struct League {
    var Hitters: Set<Hitter>

    func loadHitters() {
        ...//ingest json from bundle, 
           //store decoded Hitter objects in temp array, 
           //then append each item from temp array into League.Hitters set.
    }
}

Чтобы было ясно, мой У структуры Hitter уже есть инициализация, мне нужна помощь с использованием декодера с этого момента.

РЕДАКТИРОВАТЬ: Я нашел решение, и оно требует использования извлечения ключей JSON и связывания их с вашим CodingKeys enum. Вот мой сокращенный класс Hitter:

struct Hitter: Player, Decodable {
    //partial list of properties in JSON data
    let strPos: String
    let OBP: Float
    let wRAA: Float //weightedRunsAboveAverage
    //partial list of properties in JSON data - end
    //partial list of additional properties
    var valAboveReplacement: Float = 0.0
    var wOBP: Float {
        return OBP * Float(PA)
    }
    //partial list of additional properties - end
}

Я объявляю CodingKeys и init (decoder :) в расширении для разделения

extension Hitter {
    enum CodingKeys: String, CodingKey {
        case strPos, OBP, wRAA
    }

    convenience init(from decoder: Decoder) {
        //container links all the CodingKeys and JSONDecoder keys for proper referencing. Returns the data stored in this decoder as represented in a container keyed by the given key type
        let container = try decoder.container(keyedBy: CodingKeys.self)

        let strPos = try container.decode(String.self, forKey: .strPos)
        let OBP = try container.decode(Float.self, forKey: .OBP)
        let wRAA = try container.decode(Float.self, forKey: .wRAA)

        //pass my decoded values via a standard initializer
        self.init(strPos: strPos, OBP: OBP, wRAA: wRAA)
    }

}

Кажется, это работает прекрасно, пока я явно связать формат JSON и CodingKeys через контейнер.

1 Ответ

0 голосов
/ 03 мая 2020

Если вы разрабатываете структуру, вы получаете initializer для каждого члена бесплатно - при условии, что вы не определяете других initializers сами, но Struct автоматические инициализаторы являются внутренними. Вы должны сгенерировать memeberwise initializer при написании module, чтобы сделать его опубликованным c

"Инициализаторы по умолчанию для каждого элемента по умолчанию для типов структуры Инициализатор по умолчанию для каждого элемента по умолчанию для типа структуры считается закрытым, если любое из сохраненных свойств структуры является закрытым. В противном случае инициализатор имеет внутренний уровень доступа.

Как и в случае с инициализатором по умолчанию, приведенным выше, если вы хотите, чтобы тип структуры publi c был инициализирован с помощью инициализатора по элементам при использовании в другом модуле вы должны предоставить публикуемую c членскую инициализатор самостоятельно как часть определения типа. "

Swift Docs" Язык программирования Swift"

...