декодирование Codable в Swift

Возникли проблемы с тем, чтобы заставить это работать: я пытаюсь абстрагировать JSON-декодирование в функцию, принимая в качестве аргументов Codable плюс некоторые данные.

Поэтому мне нужно иметь следующую функцию-сигнатуру, если это возможно для этого:

func doTheJSONDecoding(cdbl: Codable, data: Data) {...}

Вот мой код, начиная с модели данных. Ниже приведены два примера....

import UIKit
import Foundation

struct MyStructCodable : Codable {
    let items : [MyValue]?
}

struct MyValue : Codable {
    let value : String?
}

let dta: Data = """
{
  "items": [
    {
      "value": "Hello1"
    }
  ]
}
""".data(using: .utf8)!

Затем два примера:

// Example 1: this code works fine !!!!!!!!!!!!!!!!!!!!!!!!

let decoder = JSONDecoder()
do {
    let result = try decoder.decode(MyStructCodable.self, from: dta)
    print(result.items?[0].value ?? "")
} catch {
    print(error)
}

// above code prints:   Hello1


// Example 2: this code does not work - WHY ???????????????

func doTheJSONDecoding(cdbl: Codable, data: Data) {
    let decoder = JSONDecoder()
    do {
        let result = try decoder.decode(cdbl, from: data)
        print(result.items?[0].value ?? "")
    } catch {
        print(error)
    }
}

let myValue = MyValue(value: "Hello2")
let myStructyCodable = MyStructCodable(items: [myValue])
doTheJSONEncoding(cdbl: myStructyCodable, data: dta)

Выброшенная ошибка находится внутри функции, она говорит:

введите здесь описание изображения

Есть ли способ сохранить сигнатуру функции (т.е. func doTheJSONDecoding(cdbl: Codable, data: Data) и все еще заставить ее работать? Любая помощь приветствуется.


person iKK    schedule 02.12.2018    source источник
comment
Хорошо, я уточнил в примере и вместо этого переименовал функцию в doTheJSONDecoding(). - Я явно хотел бы декодировать (не кодировать) - поэтому мне нужно сохранить JSONDecoder, я думаю. (т.е. у меня есть JSON-данные, и я хотел бы декодировать их в структуру). Более того, изменение сигнатуры функции на doTheJSONDecoding(cable: Decodable, data: Data) тоже не помогает...)   -  person iKK    schedule 02.12.2018
comment
cdbl должен быть конкретным типом, а не протоколом. Вы можете использовать протокол как ограничение универсального. И не любой тип, соответствующий Codable, имеет items.   -  person vadian    schedule 02.12.2018
comment
@vadian: Спасибо, я вижу, требуется тип, а не соответствие. Итак, я думаю, НЕТ СПОСОБА абстрагировать любой тип, который соответствует Decodable (или Codable в целом) - я прав в этом? Если нет - как бы я все-таки это сделал?   -  person iKK    schedule 02.12.2018
comment
stackoverflow.com/a/51058460/6630644   -  person SPatel    schedule 02.12.2018


Ответы (1)


Вот моя попытка заставить вашу функцию работать, возможно, ее можно улучшить, но она возвращает правильно декодированный объект. Обратите внимание, что он принимает тип объекта, а не объект, и именно этот тип T реализует Decodable.

func doTheJSONEncoding<T: Decodable>(cdbl: T.Type, data: Data) -> T? {
    let decoder = JSONDecoder()
    do {
        let result = try decoder.decode(cdbl.self, from: data)
        return result
    } catch {
        print(error)
    }
    return nil
}

//testing it
let myValue = MyValue(value: "Hello2")
let myStructyCodable = MyStructCodable(items: [myValue])
let decoded = doTheJSONEncoding(cdbl: MyStructCodable.self, data: dta)
print(decoded?.items?[0].value ?? "")
person Joakim Danielson    schedule 02.12.2018
comment
Большое спасибо, Йоаким. Это выглядит хорошо - я попробую. - person iKK; 02.12.2018
comment
нужен только <T: Decodable>, кодировка не нужна. - person Sulthan; 02.12.2018