簡體   English   中英

Swift - JSONDecoder - 將類 Type 作為參數傳遞給使用泛型方法解碼模型

[英]Swift - JSONDecoder - passing class Type as parameter to decode model using generic method

在這里,我們有一個場景,我在使用“JSONDecoder”解析模型類時遇到了問題。

讓我與您分享我在此示例中所做的工作以及我遇到的問題:

  • 有一個通過 Codable 派生的模型協議。
  • 一個結構模型和一個類 GenericExample
  • GenericExample 類具有以下內容:
    • 共享實例
    • typeContainer 是協議的類型
  • 還有另外兩種方法staticClassParsingdynamicClassParsing帶有一個參數 dynamicType
  • 最后,一個返回解析數據模型的通用方法。

解析模型的調用方法:

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

編譯時間錯誤:

無法推斷通用參數“T”

發生在這里

returnModelType: typeContainer.self

**更多詳情,請通過以下代碼:**

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)
    }
}

typeContainer必須是具體類型,不能是協議。 並且完成處理程序毫無意義,因為JSONDecoder是同步工作的。

要使用泛型解碼 JSON,您必須使用類似這樣的方法,強烈建議同時處理 Decoding 錯誤

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)
}

首先感謝大家的支持。 是的,我想發布我的問題的答案。

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)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM