2017-06-20 13 views
0

Alamofireを使用してURL要求を行うiOSアプリケーションがあります。私は時々間違った順序で到着する要求を見つけることができます。これは私が理解している非同期要求の性質と関係しています。要求の正しい順序を保証する方法はありますか?私はあなたが完了ハンドラを持っているので、各リクエストが完了するのを待つことができると考えていました。あるいは、サーバがタイムスタンプの少ないリクエストを破棄できるように、私は何が最善の解決策かわからない。これまで非同期要求で正しい順序を保証する方法

マイコード:

Alamofire.request(
    defaults.string(forKey: "APIurl")! + path, 
    method: httpMethod, 
    parameters: parameters, 
    encoding: JSONEncoding.default, 
    headers: headers).responseJSON 
    { response in 

    // Check if the request was successful 
    var success = false 
    if (response.result.isSuccess) { 
     let statusCode = response.response!.statusCode 
     if (statusCode == 200) { 
      success = true 
     } else { 
      showAlert("COULD_NOT_COMPLETE_TASK_TITLE", message: "TRY_AGAIN_LATER") 
     } 
    } 

} 

は、私はそう要求の順序が重要である私の場合には0から100の間の値を変更するには、スライダーを使用しています。スライダを50から60に変更するとしましょう。非同期リクエストでは、最初は60と50が実行されることがあります。これはAPIに送信され、最新の値(この場合は50)をデータベースに保存するときの問題です私の希望する値は60でしたが、

+2

を持っている

フォローthisチュートリアルあなたは非同期要求の順序を保証することはできません、あなたはリクエストが帰ってきた後に何をすべきかを取り扱い、あなたのロジックを行う必要があります。 – WeiJay

+0

注文が重要な場合は、リクエストを順次送信するか、すべてのリクエストが完了した後にレスポンスを調整する – Paulw11

+1

完了する注文を保証する唯一の方法は、最初のリクエストが完了するまで2番目のリクエストを行わないことです(これは本当に愚かな方法ですこの問題を解決するために)。 Wei Jayは正しいです。回答が来る順序に依存しないコードを記述する必要があります。しかし、それ以上の文脈はなく、その問題を解決することはできません。しかし、もう一度、今度は、あなたが何らかの順序で来るように扱う必要があることを指摘したので、おそらくそれを理解することもできます。 – Rob

答えて

0

あなたのケースではスレッドはシリアルです。それで注文は常に入力と同じになります。したがって、同じシリアルスレッド上でいくつかのオペレーションを非同期に呼び出すと、オペレーションはその順序を保持します。

あなたの場合の問題は、これらの操作を呼び出さないということです.Alamofireはそれらを呼び出しています。順序は保持されますが、応答が受信され、解析されるタイミングによって異なります。これは、呼び出される非同期操作の順序を制御できないことを意味します。

  1. あなたは次の要求を呼び出す前に完了するために、各応答を待つ必要があります。

    あなたがシリアライズ応答の2つの方法があります。あなたの応答が標準的なもの(すべて同じように見える)であれば、一連の要求を格納するマネージャが必要で、前のものが完了するまで新しい要求を呼び出さない。これは、理由がない(または少なくともあなたのケースではそのように思われる)ので、リクエストを同時に実行しないので、少し遅いかもしれません。

  2. 応答をシリアル化して、入力と同じ順序で呼び出すようにします。つまり、いつでもリクエストを呼び出し、応答はいつでも呼び出されます。しかし、応答が受信されると、他の応答が完了しているかどうかをチェックし、そうでなければ、この応答をコールバックします。これは、そこに応答をシリアル化するマネージャーがいることを意味します。応答に続いて

    let requestWrapper = RequestWrapper(request, myCallbackClosure, isCompleted: false) 
    self.requestPool.append(requestWrapper) 
    AF.performRequest(request, myInternalClosure) 
    

    :管理者は、次にように要求ラッパーのいくつかの配列にリクエストを救う

    SerializedRequestManager.performRequest(request, myCallbackClosure) 
    

だから二番目のためにあなたのようなものが必要になります(myInternalClosure)、正しいラッパーを設定してtrueに応答し、応答を配列の先頭からフラッシュする必要があります。

requestWrapper.responseData = data // Same wrapper that was just added into the array 
requestWrapper.responseError = error // Same wrapper that was just added into the array 
requestWrapper.isCompleted = true 
self.flushResponses() 

それではflushResponses:すべての応答は、配列から削除する必要があります終了

var newPool = [RequestWrapper]() // This is where all the pending items will stay 
var shouldFlushResponse = true // Will be set to false with first request that was not completed 
self.requestPool.forEach { wrapper in 
    if wrapper.isCompleted && shouldFlushResponse { 
     wrapper.callback(wrapper.responseData, wrapper.responseError) // perform response closure 
    } else { 
     shouldFlushResponse = false 
     newPool.append(wrapper) 
    } 
} 
self.requestPool = newPool 

しかし、あなたはここにマルチスレッド処理について非常に注意する必要があります。配列requestPoolのすべての操作は同じスレッドで行う必要がありますが、必要なスレッドであれば可能です。

0

あなたのケースで重要な要求の順序がある場合は、あなたの要求の順序を確認する唯一の方法であるNSOperationQueueに行ってください。ボーダーアイデア

関連する問題