简体   繁体   English

通用可解码,无需解码

[英]Generic Decodable without decoding

I am using a generic approach to decode JSONresponse generated by AlamoFire. 我正在使用一种通用方法来解码AlamoFire生成的JSONresponse。 My function is the following : 我的功能如下:

private func fetch<T: Swift.Decodable>(URLRequest: URLRequestConvertible) -> SignalProducer<T, NetworkError> {
    return Network.request(URLRequest)
        .attemptMap { JSON in
            do {
                let jsondata = try JSONSerialization.data(withJSONObject: JSON as! [String:Any], options: .prettyPrinted)
                return .success(try JSONDecoder().decode(T.self, from: jsondata))
            } catch let error {
                Logger.shared.error("Error while decoding a JSON", error: error as NSError, userInfo: ["json" : JSON,  "urlRequest" : URLRequest.urlRequest!.debugDescription])
                return .failure(.incorrectDataReturned)
            }
    }
}

For each of my request, I have created a struct that follows the Decodable protocol. 对于我的每个请求,我创建了一个遵循Decodable协议的结构。

For one request, I do not want to decode the JSON because its structure is complex and because I just need to send it back in another request, I just want to save the response in a struct for instance like this one : 对于一个请求,我不想解码JSON,因为它的结构很复杂,并且因为我只需要在另一个请求中将其发送回去,所以我只想将响应保存在这样的结构中:

struct GenericResponse: Swift.Decodable {
    let data: Data
}

where data is the response. 数据是响应。 So, I just want to take the response and put it in a struct without further decoding. 因此,我只想获取响应并将其放入结构中,而无需进一步解码。

Is it possible without braking the genericity of my function ? 是否可以不破坏我的功能的通用性? Is their a way to build a decoder that do not decode if T.self is of a certain type ? 如果T.self是某种类型,他们是否有办法构建不解码的解码器?

If you want to avoid the decoding of a specific response, you can overload the fetch function to handle that case. 如果要避免解码特定的响应,则可以重载fetch函数来处理这种情况。

See the following example where the second fetch method is overloaded to save the response data inside a struct instead of going through the decoding process. 请参见以下示例,其中第二个访存method被重载以将响应数据保存在结构中,而不是通过解码过程。

typealias JSON = [String: Any]

protocol RawResponse {
  init(data: Data)
}

// 1
func fetch<T: Decodable>(json: JSON) -> T? {
  guard let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []),
    let response = try? JSONDecoder().decode(T.self, from: jsonData) else {
      return nil
  }
  return response
}

// 2
func fetch<T: RawResponse>(json: JSON) -> T? {
  guard let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) else {
    return nil
  }
  return T(data: jsonData)
}

With this overload, if a response struct conforms to RawResponse instead of Decodable (as we don't need to actually decode the data), the fetch overload is triggered. 有了这种重载,如果响应struct符合RawResponse而不是Decodable (因为我们不需要实际解码数据),则会触发fetch重载。

struct UserResponse: Decodable {
  var username: String
}

let userJson: JSON = [
  "username": "someUser"
]
let user: UserResponse? = fetch(json: userJson) // call fetch #1
user?.username // someUser


struct GenericResponse: RawResponse {
  var data: Data
}

let notParsable: JSON = [
  "someKey": "someValue"
]
let rawData: GenericResponse? = fetch(json: notParsable) // call fetch #2
rawData?.data // 23 bytes

I dont really understand what you are trying to achieve. 我不太了解您要达到的目标。 But I faced this situation where I needed to decode using Generics. 但是我遇到这种情况,需要使用泛型进行解码。

That is why I wrote a DecoderHelper class that enables me to decode Generic Array or Generic Object (depends on your JSON response). 这就是为什么我写了一个DecoderHelper类,使我能够解码通用数组或通用对象(取决于您的JSON响应)的原因。

Maybe it can inspire you, and you will find how to optimize it or understand your situation/issue. 也许它可以激发您的灵感,您将找到如何对其进行优化或了解您的处境/问题。

final class DecoderHelper {

    static func decodeGenericObject<T: Decodable>(data: Data, completion : (Result<T, ErrorResult>) -> Void) {

        do {
            let decoder = JSONDecoder()
            let decodedData = try decoder.decode(T.self, from: data)
            completion(Result.success(decodedData))
        } catch {
            completion(Result.failure(.decoder(error: error)))
        }
    }

    static func decodeGenericArray<T: Decodable>(data: Data, completion : (Result<[T], ErrorResult>) -> Void) {

        do {
            let decoder = JSONDecoder()
            let decodedData = try decoder.decode([T].self, from: data)
            completion(Result.success(decodedData))
        } catch {
            completion(Result.failure(.decoder(error: error)))
        }
    }
}

PS: Why do you want to send it to an other request because "the JSON structure is too complex" ? PS:为什么由于“ JSON结构太复杂”而要发送给另一个请求?

It's pretty simple to parse a JSON file now with the Codable protocol. 现在使用Codable协议解析JSON文件非常简单。

Give it a try and train yourself, now that I'm comfortable with it, I love parsing JSON. 尝试一下并训练一下自己,现在,我已经习惯了,我喜欢解析JSON。

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

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