Универсальный Декодируемый без декодирования - PullRequest
0 голосов
/ 27 сентября 2018

Я использую общий подход для декодирования JSONresponse, сгенерированного AlamoFire.Моя функция заключается в следующем:

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

Для каждого моего запроса я создал структуру, соответствующую протоколу Decodable.

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

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

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

Возможно ли это, не нарушая универсальность моей функции?Есть ли способ создать декодер, который не декодирует, если T.self принадлежит к определенному типу?

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Если вы хотите избежать декодирования конкретного ответа, вы можете перегрузить функцию fetch для обработки этого случая.

См. Следующий пример, где вторая выборка 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)
}

С этой перегрузкой, если ответ 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
0 голосов
/ 27 сентября 2018

Я не очень понимаю, чего вы пытаетесь достичь.Но я столкнулся с ситуацией, когда мне нужно было декодировать с использованием Generics.

Именно поэтому я написал класс DecoderHelper, который позволяет мне декодировать Generic Array или Generic Object (зависит от вашего ответа JSON).

Может быть, это может вдохновить вас, и вы найдете, как оптимизировать его или понять вашу ситуацию / проблему.

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: Почему вы хотите отправить его на другой запроспотому что «структура JSON слишком сложна»?

Теперь довольно просто проанализировать файл JSON с протоколом Codable.

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

...