Swift - JSONDecoder - передача класса Type в качестве параметра для декодирования модели с использованием метода generi c - PullRequest
0 голосов
/ 27 марта 2020

Здесь у нас есть сценарий, в котором я сталкиваюсь с проблемой синтаксического анализа класса модели с использованием "JSONDecoder".

Позвольте мне поделиться с вами тем, что я сделал в этом примере и где я столкнулся с проблемой:

  • Существует модельный протокол, полученный через Codable.
  • Структурная модель и класс A GenericExample
  • Класс GenericExample имеет следующие вещи:
    • общий экземпляр
    • typeContainer, который является типом протокола
  • Есть еще два метода staticClassParsing и dynamicClassParsing с одним параметром dynamicType
  • В последнем методе One generi c, который возвращает анализируемая модель данных.

Вызов метода для анализа модели:

GenericExample.shared.dynamicClassParsing (Numbers.self, data: "[\ r \ n { \ "one \": \ "1 \"}, \ r \ n {\ "two \": \ "2 \"} \ r \ n] ")

Скомпилировать Ошибка времени:

Generi c параметр 'T' не может быть выведен

Произошло здесь

returnModelType: typeContainer.self

** Для более подробной информации, пожалуйста, go через следующий код: **

protocol BaseMapModel : Codable { }
struct Numbers: BaseMapModel {
    var one: String?
    var two: String?
}
class GenericExample: NSObject {

    static let shared = GenericExample()

    var typeContainer : BaseMapModel.Type?

    private override init() {
        super.init()
    }
}
extension GenericExample {

    // Static Class Parsing passed through the conversion
    func staticClassParsing() {
        let dataJson = "[\r\n{\"one\": \"1\"},\r\n{\"two\":\"2\"}\r\n]"
        convertTypeContainer(data: Data(dataJson.utf8), returnModelType: Numbers.self) { (mappedResult) in
            print(mappedResult?.one ?? "")
            print(mappedResult?.two ?? "")
        }
    }

    // Dynamic Class Parsing can't passed through the conversion
    // Error:- Generic parameter 'T' could not be inferred
    // Error Parameter:- in "returnModelType: typeContainer.self"
    func dynamicClassParsing(_ dynamicType: BaseMapModel.Type, data:String) {
        typeContainer = dynamicType.self
        convertTypeContainer(data: Data(data.utf8), returnModelType: typeContainer.self) { (mappedResult) in
            print(mappedResult?.one ?? "")
            print(mappedResult?.two ?? "")
        }
    }
}
extension GenericExample {

    private func convertTypeContainer<T : BaseMapModel>(data:Data, returnModelType: T.Type, completion: ((_ result:T?)->Void)) {

        guard let responseModel = try? JSONDecoder().decode(returnModelType.self, from: data) else {
            completion(nil)
            return
        }
        completion(responseModel)
    }
}

Ответы [ 2 ]

0 голосов
/ 28 марта 2020

Прежде всего, спасибо всем за вашу поддержку. И да, я хотел бы опубликовать ответ на мой вопрос.

class BaseMapModel : Codable { }

class Numbers: BaseMapModel {
    var one: String?
    var two: String?

    enum CodingKeys: String, CodingKey {
        case one = "one"
        case two = "two"
    }

    // Decoding
    required init(from decoder: Decoder) throws {
        let response = try decoder.container(keyedBy: CodingKeys.self)

        one = try? response.decode(String.self, forKey: .one)
        two = try? response.decode(String.self, forKey: .two)

        let superDecoder = try response.superDecoder()
        try super.init(from: superDecoder)
    }
}

class GenericExample: NSObject {

    static let shared = GenericExample()

    var defaultTypeContainer : Numbers.Type!

    var typeContainer : BaseMapModel.Type?

    private override init() {
        super.init()
    }
}

extension GenericExample {

    // Static Class Parsing passed through the conversion
    func staticClassParsing() {
        let dataJson = "[\r\n{\"one\": \"1\"},\r\n{\"two\":\"2\"}\r\n]"
        convertTypeContainer(data: Data(dataJson.utf8), returnModelType: Numbers.self) { (mappedResult) in
            print(mappedResult?.one ?? "")
            print(mappedResult?.two ?? "")
        }
    }

    // Dynamic Class Parsing passed through the conversion
    func dynamicClassParsing(_ dynamicType: BaseMapModel.Type, data:String) {
        typeContainer = dynamicType.self
        convertTypeContainer(data: Data(data.utf8), returnModelType: (typeContainer ?? defaultTypeContainer).self) { (mappedResult) in
            print((mappedResult as? Numbers)?.one ?? "")
            print((mappedResult as? Numbers)?.two ?? "")
        }
    }
}

extension GenericExample {

    private func convertTypeContainer<T : BaseMapModel>(data:Data, returnModelType: T.Type, completion: ((_ result:T?)->Void)) {

        guard let responseModel = try? JSONDecoder().decode(returnModelType.self, from: data) else {
            completion(nil)
            return
        }
        completion(responseModel)
    }
}
0 голосов
/ 27 марта 2020

typeContainer должен быть конкретным типом, это не может быть протокол. А обработчик завершения не имеет смысла, так как JSONDecoder работает синхронно.

Чтобы декодировать JSON с помощью шаблонов, вы должны использовать что-то вроде этого, настоятельно рекомендуется обрабатывать также ошибку декодирования

struct Numbers: Decodable {
    var one: String?
    var two: String?
}

class GenericExample: NSObject {
    static let shared = GenericExample()
}

extension GenericExample {
    func dynamicClassParsing<T : Decodable>(_ dynamicType: T.Type, data: String) -> Result<T,Error> {
        return Result { try JSONDecoder().decode(T.self, from: Data(data.utf8)) }
    }
}

let dataJson = """
[{"one": "1"},{"two":"2"}]
"""

let result = GenericExample.shared.dynamicClassParsing([Numbers].self, data: dataJson)
switch result {
    case .success(let numbers): print(numbers)
    case .failure(let error): print(error)
}
...