2016-10-07 8 views
0

複数のAlamofireリクエストを実行したいと思います。しかし、データ依存性のために、新しい要求は、前の処理が完了したときにのみ開始する必要があります。複数のAlamofireリクエストを次々に実行することはどのように可能ですか?

私はすでにquestionに、OperationQueueで解決されたより一般的な非同期要求の例を求めました。しかし、私はAlamofireでこれを達成することはできません。次の要求が開始される前に、要求は次のように私はOperationQueueを使用し、終了していることを保証するために

public func performAlamofireRequest(_ number: Int, success: @escaping (Int) -> Void)->Void { 
    Alamofire.request(String(format: "http://jsonplaceholder.typicode.com/posts/%i", number+1)) // NSURLSession dispatch queue 
     .responseString { response in // Completion handler at main dispatch queue? 
      if response.result.isSuccess { 
      // print("data") 
      } else if response.result.isFailure { 
      // print("error") 
      } 
      success(number) // Always leave closure in this example 
    } 
} 

let operationQueue = OperationQueue.main 
for operationNumber in 0..<4 { // Create some operations 
    let operation = BlockOperation(block: { 
     performAlamofireRequest(operationNumber) { number in 
      print("Operation #\(number) finished") 
    } 
}) 
operation.name = "Operation #\(operationNumber)" 

    if operationNumber > 0 { 
     operation.addDependency(operationQueue.operations.last!) 
    } 
    operationQueue.addOperation(operation) 
} 

ただし、出力は次のようになります。明確ではありません

Operation #0 finished 
Operation #3 finished 
Operation #2 finished 
Operation #1 finished 

正しい。

Alamofireでこれを実現するにはどうすれば可能ですか?

答えて

2

問題がrelated questionあなたが提起のようにちょうど同じである。文書化されているように操作依存関係は、仕上げ作業にありますが、あなたは操作は非同期で、将来の実行要求をディスパッチした後に終了コード(オペレーションあなたを書かれています作成され、キューに追加されると、依存関係によって設定された順序で終了しますが、要求はAlamofireの基になるNSURLSessionによって同時に発生します。あなたはシリアル実行が必要な場合は

は、あなたは、例えば、以下の操作を行うことができます。

// you should create an operation queue, not use OperationQueue.main here – 
// synchronous network IO that would end up waiting on main queue is a real bad idea. 
let operationQueue = OperationQueue() 
let timeout:TimeInterval = 30.0 

for operationNumber in 0..<4 { 
    let operation = BlockOperation { 
     let s = DispatchSemaphore(value: 0) 
     self.performAlamofireRequest(operationNumber) { number in 
      // do stuff with the response. 
      s.signal() 
     } 

     // the timeout here is really an extra safety measure – the request itself should time out and end up firing the completion handler. 
     s.wait(timeout: DispatchTime(DispatchTime.now, Int64(timeout * Double(NSEC_PER_SEC)))) 
    } 

    operationQueue.addOperation(operation) 
} 

様々な他のソリューションは、間違いなく重複をin connection to this questionを議論しています。 Alamofire-Synchronousもあります。

+0

これは機能し、またはっきりとした説明です!私はまた、操作キューがメインキューを使用してはならないことに同意します。しかし、もし 'OperationQueue.main'が使用されていれば、私はUIブロックを期待していますが、AlamofireのcompletionHandlerはまったく呼び出されていない(したがって、セマフォは通知されません)ようです。私はこのように実装しませんが、なぜ動作しないのか理解していただければ幸いです。 – Taco

+0

上記のブロック操作を実行するために 'OperationQueue.main'を使用した場合、コールバックが起動されない理由は、セマフォ' wait '呼び出しはブロック操作の内部で行われ、メインキューをブロックします。タイムアウトがなければ、このシナリオではデッドロックが発生します。このセマフォーベースのルートでも可能な醜い微妙なバグがもう1つあります。上記のタイムアウト時間が要求を実行しているNSURLSession/NSURLRequestのタイムアウト時間より短い場合、ブロック操作が完了し、後でいつかコールバックが起動されます。私はセマフォから離れることができます:) – mz2

+0

ああ、もちろん。どうもありがとう! – Taco

関連する問題