2016-11-19 66 views
1

由於2天感覺我正在搜索整個網絡來解決我的問題與多個http請求。所以我的工作流程是這樣的:斯威夫特 - 多循環鏈式http請求

  1. 上傳圖像到服務器

    • 響應=有任務ID
  2. GET請求到服務器的任務ID XML格式檢查此任務的狀態。

    • 響應=在狀態可能是 「已完成」, 「進行中」, 「排隊」
    • 如果狀態= 「已完成」 的XML格式 - !重試第2步
    • 如果狀態==「已完成「 - 去從resultUrl

我最後一次嘗試步驟3

  • 下載的結果是使用PromiseKit以一種乾淨的方式鏈接請求,如本文中所述:Chain multiple Alamofire requests。但是如果狀態還沒有完成,我不知道如何每2-5秒循環第二步。

    是否有針對此工作流的推薦解決方案?這是我的測試與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) 
        } 
    } 
    

    現在可以做的S TANDARD Promise東西與上面,例如:

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

    在上面的幾個注意事項:

    • 我打電話fulfillData。通常你會有一些模型對象或類似的東西,但我不確定你的情況適合什麼。

    • 我顯然沒有做任何XML解析。但是,你顯然會解析迴應,並相應地確定taskCompleted

    • 儘管您說任務的狀態可以是「排隊」,「正在進行」和「已完成」,但我認爲如果排隊的任務失敗,您最終會讓服務器的進程添加一些錯誤處理。所以,我還添加了一個taskFailed錯誤。盡你所能去做。

    • 我對最大重試次數做了一些假設,以及在發生網絡錯誤時該怎麼辦。顯然,將這​​些條件定製爲適合您的情況。

    所以,不要迷失在我的例子的細節,而是着眼於更廣闊的畫面,即你可以創建一個Promise並通過兩個fulfillreject關閉的例行單獨的例程,實際執行重試邏輯。

    +0

    謝謝。這是我的案例的一個完美例子。現在我可以清理我的解決方法來取回乾淨的代碼! – kaaPe