2016-11-19 1 views
1

2 일 이후로 여러 웹 요청을 통해 문제를 해결하기 위해 전체 웹을 검색하고 있습니다. 그래서 내 워크 플로우는 다음과 같습니다스위프트 - 루프가있는 다중 체인 http 요청

  1. 가 서버

    • 응답 = 작업 ID로 서버에 작업 ID
  2. GET 요청과 XML 형식으로 이미지를 업로드 이 작업의 상태를 확인하십시오.

    • 응답 = 상태는 "대기"
    • "진행 중"상태 = "완료"가 "완료"할 수있는 XML 형식 -! 다시 시도 2 ​​단계
    • 상태 == "완료 한 경우 "- resultUrl

내 마지막 시도에서 3

  • 다운로드에게 결과를 단계로 이동하는 것은를 사용하는 것이 었습니다은이 게시물에 설명 된 것처럼 깨끗한 방법으로 요청을 연결합니다 : 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) 
        } 
    } 
    

    당신은 지금 할 수있는을의 위, 예컨대와 tandard Promise 물건 : 위의

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

    몇 가지주의 사항 :

    • 나는 Datafulfill를 호출하고 있습니다. 대개는 모델 객체 등을 가지고있을 것이지만, 귀하의 경우에 무엇이 적절했는지 확신 할 수 없습니다.

    • 분명히 XML 구문 분석을 수행하지 않습니다. 하지만 분명히 응답을 구문 분석하고 이에 따라 taskCompleted을 결정할 것입니다.

    • 작업 상태가 "대기", "진행 중"및 "완료"일 수 있다고했는데 대기열에있는 작업이 실패하면 결국 서버 프로세스에서 오류 처리를 추가한다고 가정했습니다. 그래서 taskFailed 오류도 추가했습니다. 당신이 적합하다고 생각하는대로하십시오.

    • 최대 재시도 횟수와 네트워크 오류가 발생했을 때 수행 할 작업에 대해 몇 가지 가정을했습니다. 분명히,이 조건들을 귀하의 경우에 맞는 것으로 사용자 정의하십시오. 당신이 Promise를 만들고에 두 fulfillreject 클로저를 전달하는 루틴을 가질 수

    그래서, 내 예제의 세부 사항에서 분실하지 않고, 즉, 더 넓은 그림에 초점을 재시도 논리를 실제로 수행하는 별도의 루틴.

    +0

    감사합니다. 내 사건의 완벽한 예입니다. 이제 깨끗한 코드를 얻기 위해 해결 방법을 정리할 수 있습니다! – kaaPe