web-dev-qa-db-ja.com

再試行でAlamofireリクエストを行う方法はありますか

Alamofireのリクエスト/レスポンスが処理されるコードの場所がたくさんあります。

いくつかの断続的な問題が原因で、この各要求は失敗する可能性があります(最も一般的なのは不安定なネットワークです)。

救済の前にリクエストを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()
   }
}

しかし、私はこのアプローチA LOTをいくつかの理由で嫌っています。最も明白なのは、要求タイプごとにそのようなコードを実装する必要があることです(そして、15のようなものがあります)。

私は(変更が最小限で邪魔にならないような)何かをする方法があるかどうか好奇心が強い

let request = Alamofire.request(..., **3**) 
12
Victor Ronin

Swiftで得られる構文糖のビットの1つは、これを使用できることです。

public func updateEvents(someNormalParam: Bool = true, someBlock: (Void->Void))

このような:

updateEvents(someNormalParam: false) {...}

ブロックがupdateEvents関数の()の外にあることに注意してください。これは、ブロックが関数の宣言で最後のものである場合にのみ機能します。

つまり、Alamofireリクエストなどのブロックが発生した場合、それを再試行機能で効果的にラップできます。少し複雑な問題の1つは、ブロック内でブロックを呼び出したい場合です。大したことではない:

func retryWrapper(alamoBlock: (Void->Request)) {
   alamoblock().responseJSON() {
       //Your retry logic here
   }
}

そして、あなたはそのようにそれを使います:

retryWrapper() {
    Alamofire.request(method, targetUrl, parameters: parameters, encoding: encoding)
}

つまり、Alamofireの呼び出しを見つけて{}でラップし、前にretryWrapper()を配置するだけです。再試行ロジック自体は一度だけです。

3
Carlos

Alamofire 4.0には、使用可能なRequestRetrierプロトコルがあります。

https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md#request-retrier

例:

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

私も同じ問題を抱えており、RequestRetriershouldメソッド、および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)
    }
}
4
Carla Camargo

リクエストリトリエが機能するためのラッパークラスを1つ作成しました。 https://Gist.github.com/daljeetseera/7ce2b53b8a88d8a5e9b172c0495c6455

また、リクエストに必要なセッションマネージャーでリクエストリトリーバーを使用しました。

static let sharedManager: SessionManager = {
        let configuration = URLSessionConfiguration.default
        let manager = Alamofire.SessionManager(configuration: configuration)
        let requestRet = NetworkRequestRetrier()
        manager.retrier = requestRet
        return manager
    }()

1
Daljeet Seera