简体   繁体   English

如何快速检查类型并将其转换为可解码

[英]How to check and cast a type to Decodable in swift

I want to make a networking request in which I could control the response is JSON raw value [String: Any or the Decodable .我想发出一个网络请求,我可以在其中控制响应是 JSON 原始值[String: AnyDecodable

Here is the example:这是示例:

func reqest<T>(endpoint: EndPoint, completion: @escaping (Result<T, Error>) -> Void) {
   session.dataTask(with: request) { (data, response, error) in

       if T.self is Decodable.Type {
           try? JSONDecoder().decode(T.self, from: data)
       } else {
           try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
       }
   }.resume()
}

then when I want JSON value I just call with T as [String: Any] or just use any model confirm Decodable protocol.然后当我想要 JSON 值时,我只需将T作为[String: Any]调用或仅使用任何模型确认可Decodable协议。

The question is for this line:问题是针对这一行:

try? JSONDecoder().decode(T.self, from: data)

How to cast T to Decodable ?如何将TDecodable

I know to use:我知道使用:

func reqest<T: Decodable >(endpoint: EndPoint, completion: @escaping (Result<T, Error>) -> Void)

but [String: Any] isn't Decodable .但是[String: Any]不是Decodable

Or any better solution to achieve what I want?或者任何更好的解决方案来实现我想要的? thanks.谢谢。

I would recommend to use overload for the reqest(endpoint:completion:) function to achieve what you want.我建议对reqest(endpoint:completion:)函数使用重载来实现你想要的。

A structure that I would like for example is this:例如,我想要的结构是这样的:

enum ResponseError: Error {
    case noData
    case typeMismatch
}

func reqest<T>(endpoint: EndPoint, completion: @escaping (Result<T, Error>) -> Void) {
    baseReqest(endpoint: endpoint) { result in
        switch result {
        case .success(let data):
            do {
                guard let json = try JSONSerialization.jsonObject(with: data) as? T else {
                    completion(.failure(ResponseError.typeMismatch))
                    return
                }
                completion(.success(json))
            } catch {
                completion(.failure(error))
            }
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

func reqest<T: Decodable>(endpoint: EndPoint, completion: @escaping (Result<T, Error>) -> Void) {
    baseReqest(endpoint: endpoint) { result in
        switch result {
        case .success(let data):
            do {
                let response = try JSONDecoder().decode(T.self, from: data)
                completion(.success(response))
            } catch {
                completion(.failure(error))
            }
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

private func baseReqest(endpoint: EndPoint, completion: @escaping (Result<Data, Error>) -> Void) {
    session.dataTask(with: request) { (data, response, error) in
        if let error = error {
            completion(.failure(error))
            return
        }
        guard let data = data else {
            completion(.failure(ResponseError.noData))
            return
        }
        completion(.success(data))
    }.resume()
}

That way you can have generic response handling code in baseReqest(endpoint:completion:) function and separate only the response parsing in the other two functions.这样你就可以在baseReqest(endpoint:completion:)函数中拥有通用的响应处理代码,并在其他两个函数中只分离响应解析。

Then calling reqest(endpoint:completion:) function could be然后调用reqest(endpoint:completion:)函数可以是

  • using [String: Any] as response type:使用[String: Any]作为响应类型:
reqest(endpoint: endpoint) { (result: Result<[String: Any], Error>) in
    // Handle result
}
  • using [[String: Any]] as response type:使用[[String: Any]]作为响应类型:
reqest(endpoint: endpoint) { (result: Result<[[String: Any]], Error>) in
    // Handle result
}
  • and also using a Decodable object as response type:并且还使用Decodable对象作为响应类型:
struct Response: Decodable {}

reqest(endpoint: endpoint) { (result: Result<Response, Error>) in
    // Handle result
}

Do it in Swift way.以 Swift 的方式来做。 Use the struct Codable (that gives you the Decodable together).使用 struct Codable (它为您提供 Decodable )。

For example:例如:

 struct testStruct: Codable {
   public var testString:String!
   public var testAny:Any!
   init(
          testString:String!,
          testAny:Any!
       )
   {
       self.testString = testString
       self.testAny = testAny
   }

Then you initialize it with this:然后你用这个初始化它:

var testStructToUse:[testStruct] = []

From here you can populate it with append method:从这里您可以使用 append 方法填充它:

testStructToUse.append(testStruct(testString: "any String", testAny: "any value"))

And encode with JSONencoder并使用 JSONencoder 进行编码

let jsonData = try JSONEncoder().encode(testStruct)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM