Какой тип использовать для универсального декодируемого класса - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть некоторые основы в Swift, и сейчас я пытаюсь освоить разработку под iOS.В настоящее время я работаю в небольшом приложении, которое будет запрашивать ресурс у созданного мной API, который возвращает json из:

struct A : Codable {
    let name: String
    let age: Int
}

struct B : Codable {
    let something: String
}

Эти структуры определены и для API, и для приложения.Поскольку я всегда запрашиваю один и тот же API, я подумал об обёртывании той части, которая запрашивает у API некоторые ресурсы, и расшифровал ее, чтобы у меня был экземпляр структуры для использования в моем обратном вызове.Вот этот метод:

static func getContent(urlRequest: URLRequest, decodable: Decodable, completion: @escaping (Codable?, ErrorEnum?)->Void) {
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)

    let task = session.dataTask(with: urlRequest) {
        data, response, error in

        guard let data = data else {
            completion(nil, .noData) // Handling errors in an enum
            return 
        }
        let decoder = JSONDecoder()
        if let full = try? decoder.decode(decodable, from: data) {
            completion(full, nil)
        }
    }

    task.resume()
}

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

static func getContent(urlRequest: URLRequest, decodable: Decodable.Type, completion: @escaping (Codable?, ErrorEnum?)->Void)

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

if let full = try? decoder.decode(decodable, from: data) {
    completion(full, nil)
}

, нокажется, ничто не удовлетворяет компилятор ... И просмотр метода decode внутри исходного кода Swift не помог мне так сильно, как это требуется T.Type where T is Decodable

Я хочу иметь возможность использовать это следующим образом:

static func getA() {
    guard let url = URL(string: "http://localhost/a") else { return }

    let urlRequest = URLRequest(url: url)
    getContent(urlRequest: urlRequest, decodable: A.self) {
        a, error in

        guard a = a else { return }
        print(a.name!)
    }
}

Ты хоть представляешь, как мне этого добиться?Я также не знаю, как назвать этот тип параметров или что искать в Google, что может привести меня к ответу (отсутствие словарного запаса).

Спасибо!

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Вы можете использовать это:

func genericRequest<T: Decodable>(_ request: URLRequest, completion: @escaping APIGenericRequestCompletion<T>) {

        Alamofire.request(request).responseData { (response) in


            guard let data = response.data else {
                completion(nil)
                return
            }


            do {
                let decodedObject = try JSONDecoder().decode(T.self, from: data)

                completion(decodedObject)
            } catch {
                completion(nil)
            }

        }
    }

, где APIGenericRequestCompletion равно:

typealias APIGenericRequestCompletion<T: Decodable> = (_ result: T?) -> Void

Затем вы используете его как:

genericRequest(request) { (decodableObjectResponse) in
            // your code here
}
0 голосов
/ 20 февраля 2019

попробуйте просто добавить generic .Type из Codable и использовать его тип в качестве параметра для передачи foo.self

static func getContent<T: Codable>(urlRequest: URLRequest, decodable: T.Type, completion: @escaping (T?, ErrorEnum?)->Void) {
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)

let task = session.dataTask(with: urlRequest) {
    data, response, error in

    guard let data = data else {
        completion(nil, .noData) // Handling errors in an enum
        return
    }
    let decoder = JSONDecoder()
    if let full = try? decoder.decode(decodable, from: data) {
        completion(full, nil)
    }
}
task.resume()
}
...