2016-11-19 16 views
1

2日以来、私は複数のHTTPリクエストで自分の問題を解決するためにウェブ全体を探しているように感じています。だから私のワークフローは次のようになります。Swift - ループで複数のチェーンのHTTPリクエスト

  1. がサーバー

    • レスポンス=タスクIDを持つサーバへのタスクID
  2. GETリクエストを使用してXMLフォーマットに画像をアップロードこのタスクのステータスを確認します。 != "完了"

    • レスポンス=ステータスが "進行中"、 "完了" することができ、XMLフォーマット、 "キュー"
    • は、ステータスの場合 - ステータス場合には、ステップ2
    • を再試行してください==「完了「 - 3
  3. resultUrl

    から結果をダウンロード

私の最後の試みはを使用していたに進みますを使用して、この投稿に記載されているようなクリーンな方法でリクエストを連鎖させてください:Chain multiple Alamofire requestsしかし、ステータスがまだ完了していない場合は、2〜5秒ごとに2番目の手順をループする方法がわかりません。

このワークフローの推奨ソリューションはありますか?これは私が成功したループせずに要求をチェーンPromiseKit、と私のテストでした:

let request = Client.imageUploadRequest(image: imageView.image!) 
let httpOperation = HTTPOperation(withRequest: request) 

httpOperation.sendRequest().then() { result -> Promise<String> in 
    let xml = SWXMLHash.parse(result) 
    let id = self.getXMLAttribute(from: xml, with: "id")! 
    let taskStatusrequest = Client.getTaskStatusRequest(withTaskID: id) 
    let httpOperation = HTTPOperation(withRequest: taskStatusrequest) 

    return httpOperation.sendRequest() 
} 
// Loop this result if status != "Completed" 
.then { result -> Promise<Data> in 
    let xml = SWXMLHash.parse(result) 
    let downloadUrl = self.getXMLAttribute(from: xml, with: "resultUrl")! 
    let downloadRequest = Client.getDownloadRequest(withUrl: downloadUrl) 
    let httpOperation = HTTPOperation(withRequest: downloadRequest) 

    // if status != "Completed" don't return, retry this step 
    return httpOperation.downloadData() 
} 
.then { _ -> Void in 
    // Refresh View with data 
} 

答えて

1

基本的な考え方は、問題の要求を再試行し、一定の基準が満たされた場合のみ、約束を果たしルーチンを作成することです:

/// Attempt a network request. 
/// 
/// - Parameters: 
/// - request: The request. 
/// - maxRetries: The maximum number of attempts to retry (defaults to 100). 
/// - attempt: The current attempt number. You do not need to supply this when you call this, as this defaults to zero. 
/// - fulfill: The `fulfill` closure of the `Promise`. 
/// - reject:  The `reject` closure of the `Promise. 

private func retry(_ request: URLRequest, maxRetries: Int = 100, attempt: Int = 0, fulfill: @escaping (Data) -> Void, reject: @escaping (Error) -> Void) { 
    guard attempt < maxRetries else { 
     reject(RetryError.tooManyRetries) 
     return 
    } 

    Alamofire.request(request) 
     .validate() 
     .responseData { response in 
      switch response.result { 
      case .success(let value): 
       let taskCompleted = ...   // determine however appropriate for your app 
       let serverReportedFailure = ... 

       if serverReportedFailure { 
        reject(RetryError.taskFailed) 
       } else if taskCompleted { 
        fulfill(value) 
       } else { 
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { 
         self.retry(request, maxRetries: maxRetries, attempt: attempt + 1, fulfill: fulfill, reject: reject) 
        } 
       } 
      case .failure(let error): 
       reject(error) 
      } 
    } 
} 

/// Error codes for retrying of network requests. 

enum RetryError: Error { 
    case tooManyRetries 
    case taskFailed 
} 

次に、上記によって満たされる約束を作成する方法を持つことができます。

/// Create a promise for a network request that will be retried until 
/// some criteria is met. 
/// 
/// - Parameter request: The request to be attempted. 
/// - Returns: The `Promise`. 

private func retry(for request: URLRequest) -> Promise<Data> { 
    return Promise { fulfill, reject in 
     self.retry(request, fulfill: fulfill, reject: reject) 
    } 
} 

あなたは今の操作を行うことができます上記とtandard Promiseもの、例えば:

retry(for: request).then { data in 
    print("received \(data)") 
}.catch { error in 
    print("error: \(error)") 
} 

上記ではいくつかの注意事項:

  • 私はDatafulfillを呼んでいます。通常はモデルオブジェクトなどがありますが、あなたの場合には何が適切かはわかりません。

  • 私は明らかにXML解析を行っていません。しかし、あなたは明らかに応答を解析し、それに応じてtaskCompletedを決定するでしょう。

  • タスクのステータスが「キューイング」、「進行中」、「完了」のいずれかであると言われましたが、キューに入れられたタスクが失敗した場合には、そこで、taskFailedというエラーも追加しました。あなたが合っているようにしてください。

  • ネットワークエラーが発生した場合のリトライ回数と対処方法については、いくつかの前提があります。明らかに、これらの条件をあなたの場合に適切なものにカスタマイズしてください。あなたがPromiseを作成し、2つのにfulfillrejectクロージャを渡すルーチンを持つことができること

だから、私の例の詳細で迷子にしないが、むしろ、すなわち、より広範な絵に焦点を当てますリトライロジックを実際に実行する独立したルーチン。

+0

ありがとうございます。これは私の場合の完璧な例です。今私はクリーンなコードを取得するために私の回避策をクリーンアップすることができます! – kaaPe

関連する問題