Как бросить внутрь замыкания в функции?

#swift #closures #throw

#swift #замыкания #бросить

Вопрос:

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

Я хотел, чтобы эта функция выдавала, чтобы я мог просто использовать do catch для обработки ошибок или случаев успеха с разными типами.

Это моя функция:

 func performRequest<T: Codable>(_ request: URLRequest, ofType: T.Type) throws -> T{
    URLSession.shared.dataTask(with: request) {(data, response, err) in
        if let err = err {throw err}
        if let response = response as? HTTPURLResponse {
            if response.statusCode != 200 {
                // Here I would return the value
            } else {
                // here I would throw the error
            }
        }
        }.resume()
}
  

Но в первой строке после URLSession.shared.dataTask я получил эту ошибку:

Недопустимое преобразование из функции выбрасывания типа ‘(_, _, _) throws -> ()’ в тип функции без выбрасывания ‘(Данные?, URLResponse?, Ошибка?) -> Void’

Я понимаю, что это потому, что я пытаюсь вставить функцию dataTask внутрь, но мой вопрос в том, есть ли какой-либо способ выполнить это?

Комментарии:

1. Вы не можете throw внутри обработчика завершения URLSession.shared.dataTask , потому что тип этого обработчика завершения уже определен, и это не throws функция.

Ответ №1:

Ваш вызов является асинхронным. Вам нужно вернуть данные в замыкание после получения данных. Для проверки, был ли вызов успешным или нет, вы можете использовать недавно введенный Result тип, поэтому вам не нужно throw

 func performRequest<T: Codable>(_ request: URLRequest, completion: @escaping (Result<T, Error>) -> Void) {
    URLSession.shared.dataTask(with: request) { (data, response, err) in
        if let err = err {
            return completion(Result.failure(err))
        }
        if let response = response as? HTTPURLResponse {
            if response.statusCode == 200 { // 200 is code for OK btw
                return completion(Result.success(someValueOfTypeT))
            } else {
                return completion(Result.failure(yourError))
            }
        }
    }.resume()
}
  

Использование: (обратите внимание, что тип T может быть выведен из объявления замыкания)

 performRequest(someRequest) { (result: Result<SomeTypeConformsToCodable, Error>) in
    switch result {
    case .success(let value):
        // work with value
    case .failure(let err):
        print(err)
    }
}
  

Комментарии:

1. Роберт Дреслер большое вам спасибо за ваш ответ, я попробовал этот подход с использованием функции throwing, потому что я вызываю эту функцию внутри другой функции, которая также принимает completionHandler с параметром типа Result , поэтому я подумал, что выбрасывание будет удобнее для чтения, как только мне придется отправлять результат внутри другого результата, теперь я понимаю, что это правильный путь … спасибо