Есть ли способ сделать запросы Alamofire с повторными попытками
у меня есть много мест в коде, где обрабатывается запрос/ответ Alamofire.
каждый из этих запросов может завершиться неудачей из-за некоторой прерывистой проблемы (наиболее распространенной является flaky network).
Я хотел бы иметь возможность повторить запросы 3 раза, прежде чем выходить из игры.
простым методом было бы иметь что-то вроде этого
var errorCount = 0
func requestType1() {
let request = Alamofire.request(...).responseJSON { response in
if (isError(response) && errorCount < 3) {
errorCount += 1
request1()
}
if (isError(response)) {
handleError()
}
handleSuccess()
}
}
однако мне очень не нравится этот подход по нескольким причинам. Наиболее очевидным является то, что Мне нужно реализовать такой код для каждого типа запроса (и у меня что-то вроде 15 из них).
мне любопытно, есть ли способ сделать что-то вроде (где изменения минимальны и не навязчиво)
let request = Alamofire.request(..., **3**)
4 ответов
один из кусочков синтаксического сахара, который вы получаете с Swift, вы можете использовать это:
public func updateEvents(someNormalParam: Bool = true, someBlock: (Void->Void))
такой:
updateEvents(someNormalParam: false) {...}
Примечание блок находится за пределами () функции updateEvents, вопреки где вы обычно ожидаете. Он работает только в том случае, если блок является последним в объявлении функции.
это означает, что если у вас есть блок, такой как ваш запрос Alamofire, вы можете эффективно обернуть его с помощью функции повтора. Один немного усложняет проблему то, что вы хотите вызвать блок внутри блока. Ничего страшного:
func retryWrapper(alamoBlock: (Void->Request)) {
alamoblock().responseJSON() {
//Your retry logic here
}
}
и вы используете его так:
retryWrapper() {
Alamofire.request(method, targetUrl, parameters: parameters, encoding: encoding)
}
означает, что все, что вам нужно сделать, это найти ваши вызовы Alamofire и обернуть их в { } и поставить retryWrapper() раньше. Сама логика повторных попыток существует только один раз.
Alamofire 4.0 имеет RequestRetrier
протокол, который вы можете использовать.
пример:
class OAuth2Handler: RequestAdapter, RequestRetrier {
public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: RequestRetryCompletion) {
if let response = request.task.response as? HTTPURLResponse, response.statusCode == 401 {
completion(true, 1.0) // retry after 1 second
} else {
completion(false, 0.0) // don't retry
}
// Or do something with the retryCount
// i.e. completion(request.retryCount <= 10, 1.0)
}
}
let sessionManager = SessionManager()
sessionManager.retrier = OAuth2Handler()
sessionManager.request(urlString).responseJSON { response in
debugPrint(response)
}
у меня была такая же проблема, и я получил запросы на повторное использование RequestRetrier
, should
способ и request.retryCount
. Что-то вроде этого:
// MARK: - RequestRetry
public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
lock.lock() ; defer { lock.unlock() }
if let response = request.task?.response as? HTTPURLResponse{
if response.statusCode == 401 {
requestsToRetry.append(completion)
getToken { (expires, _) in
_ = SessionCountdownToken.sharedInstance.startCount(expirationTime: expires)
}
} else {
if request.retryCount == 3 { completion(false, 0.0 ); return}
completion(true, 1.0)
return
}
} else {
completion(false, 0.0)
}
}
Ну, что я сделал, это следующее, если запрос терпит неудачу, я отправляю неудачное уведомление тому, кто сделал запрос. Затем он отвечает за повторное выполнение запроса. Оказалось, что это намного проще.
Alamofire.request(.GET, urlString, parameters: params, headers: defaultHeaders)
.validate()
.responseJSON
{
response in
switch response.result
{
case .Success:
print("Request Successful")
let json = JSON(data:response.data!)
NSNotificationCenter.defaultCenter().postNotificationName(SUCCESS_NOTIFICATION, object: movieArray)
case .Failure(let error):
print("Request Failed with error \(error)")
NSNotificationCenter.defaultCenter().postNotificationName(FAILURE_NOTIFICATION, object: error)
}
}