Невозможно вызвать 'decode' со списком аргументов типа '(Codable.Type? - PullRequest
0 голосов
/ 22 января 2019

Я рефакторинг ( пытаюсь ) некоторый сетевой код, сделанный бывшим коллегой, и я хотел использовать новый JSONDecoder.

Его сетевой код обернут в функцию getData:

func getData(modelToReturn:Proto.Type, configuredRequest:URLRequest) {

Как видно из подписи, в этом методе вы можете указать возвращаемую модель (то есть модель, которая должна десериализовать полученный JSON: я не могу сказать лучше, надеюсь, вы все равно поняли :-) ).

В этом случае Proto - это протокол, которому соответствует любая модель.

например.

struct GroceryModel:Proto{
  //...
}

Затем метод был назван так:

net.getData(modelToReturn: GroceryModel.self, configuredRequest: grocery)

После вызова GroceryModel.self был назначен члену класса net (memberToReturn:Proto.Type?), а затем JSON протестирован на соответствие структуре модели с неисправным инициализатором:

 if let instance = modelToReturn?.init(json:jsonResult){...

Я провел небольшой тест со следующим протоколом:

struct Test: Codable {
    let name: String
    let testers: [String]
}

и я заменил большую часть исходного кода этой единственной строкой:

let test = try? JSONDecoder().decode(modelToReturn, from: jsonData)

Моя идея состояла в том, чтобы передать Codable.self в качестве первого параметра функции getData, но я получил ошибку в этой последней строке:

Cannot invoke 'decode' with an argument list of type '(Codable.Type?, from: Data)'

Итак, как мне правильно передать мою модель, чтобы ее можно было использовать из функции decode?

Я должен сказать, что я вручную протестировал эту строку, просто заменив modelToReturn на Test.self, и ошибка исчезла.

1 Ответ

0 голосов
/ 22 января 2019

Вы можете использовать дженерики, как показано ниже.

protocol Proto {
}

struct Test: Codable, Proto {
    let name: String
    let testers: [String]
}

func getData<T>(type: T.Type, configuredRequest:URLRequest?) where T : Decodable {
    let data = """
{
    "name": "a test",
    "testers": ["mike", "bob"],
}
""".data(using: .utf8)!
    let test = try? JSONDecoder().decode(type, from: data)
    debugPrint(test)
}

getData(type: Test.self, configuredRequest: nil)

Отредактировано.

Как прокомментировано, вы хотите, чтобы Type был членом класса, который имеет getData.В этом случае вы можете применить дженерики к определению класса, как показано ниже.

class DataFetcher<T> where T: Decodable {
    func getData(configuredRequest:URLRequest?) {
        let data = """
{
    "name": "a test",
    "testers": ["mike", "bob"],
}
""".data(using: .utf8)!
        let test = try? JSONDecoder().decode(T.self, from: data)
        debugPrint(test)
    }
}

DataFetcher<Test>().getData(configuredRequest: nil)
...