2016-11-11 6 views
0

확인의 모든 단계에서 progressHUD를 업데이트, 나는방법 Alamofire으로 순차적 요청을 수행하고 스위프트 3

내가 Alamofire 4.x의 (스위프트 3, 엑스 코드 8.1을 사용하고 있습니다 ...이 일을 통해 너트려고하고있다). 가져 와서 인증을 필요로하는 사이트에서 여러 HTML 요청을 구문 분석해야합니다 (불행히도 json API 없음). 그러면 HTML이 Fuzi와 구문 분석되며이 진행 과정에는 다소 시간이 걸릴 수 있으므로 ProgressHUD (정확한 PKHUD)를 사용하여 사용자에게 무슨 일이 일어나는지 알릴 수 있습니다. 나는 또한 인증 뒤에 있지 않은 html을 잡을 필요가있다.

전체 네트워크 프로세스를 처리하고 데이터를 구문 분석하기 위해 구조체와 함수를 만들었습니다.

요청을 수행하고 필요한 데이터를 가져올 수 있었지만 적시에 HUD 업데이트를 만드는 방법을 알 수 없었습니다. 이 설정으로

let myData = MscRequest.init(
    profile: true, 
    log: true, 
    times: false, 
    records: true, 
    recordsToFetch: RecordsToFetch.init(
    provinces: ["NB", "CA"], 
    ageGroups: ["20", "25", "30", "35", "40"], 
    genders: ["M", "F"]), 
    user: MscUser.init(
    username: "SomeUserName", 
    password: "SomePassword"), 
    parentView: self 
) 

MyMSCProvider.fetchData(data: myData) 

: 나는 TableViewController에서 MscRequest 설정을하고자하고 일련 그래서 같은 요청을 시작,이 설정에서

import Alamofire 
import Fuzi 
import PKHUD 

struct MyMSCProvider { 

static let baseUrl = "http://mastersswimming.ca" 

//I tried with or without a custom queue - same result 
static let processingQueue = DispatchQueue(label: "com.colddiver.processing-queue", qos: .utility) 

static func fetchData(data: MscRequest) { 

    if data.profile || data.log { 

     //Authenticate first! 
     HUD.show(.labeledProgress(title: "Authenticating", subtitle: "")) 

     let requestUrl = "\(baseUrl)/MyMscPage.jsp" 
     let parameters = ["locale": "en", "username": data.user.username, "password": data.user.password] 

     Alamofire.request(requestUrl, method: .post, parameters: parameters).responseData(
      queue: processingQueue, 
      completionHandler: 
      { response in 


       // Now on the processingQueue you created earlier. 
       print("THREAD: \(Thread.current) is main thread: \(Thread.isMainThread)") 

       switch response.result { 
       case .success: 

        if data.profile { 
         DispatchQueue.main.async { 
          HUD.show(.labeledProgress(title: "Getting Profile", subtitle: "")) 
         } 
         let userProfile = parseProfile(data: response.data!, user: data.user) 
         print(userProfile) 
        } 

        if data.log { 
         DispatchQueue.main.async { 
          HUD.show(.labeledProgress(title: "Getting Log", subtitle: "")) 
         } 
         fetchLog() 
        } 

        if data.records { 
         DispatchQueue.main.async { 
          HUD.show(.labeledProgress(title: "Getting Records", subtitle: "")) 
         } 
         fetchRecords(recordsToFetch: data.recordsToFetch) 
        } 

        if data.times { 
         DispatchQueue.main.async { 
          HUD.show(.labeledProgress(title: "Getting Times", subtitle: "")) 
         } 
         print("Fetching times is not implemented yet") 
        } 

        DispatchQueue.main.async { 
         HUD.flash(.success) 
        } 


       case .failure(let error): 
        HUD.flash(.error) 
        print("Alamofire request failed") 
        print(error) 
       } 
     } 
     ) 


    } else { 
     //Just fetch - no need to authenticate first 
     if data.records { 
      DispatchQueue.main.async { 
       HUD.show(.labeledProgress(title: "Getting Records", subtitle: "")) 
      } 
      fetchRecords(recordsToFetch: data.recordsToFetch) 
     } 

     if data.times { 
      print("Fetching times is not implemented yet") 
     } 

     DispatchQueue.main.async { 
      HUD.flash(.success) 
     } 
    } 

} 

static func fetchRecords(recordsToFetch: RecordsToFetch) { 

    for province in recordsToFetch.provinces { 
     for ageGroup in recordsToFetch.ageGroups { 
      for gender in recordsToFetch.genders { 

       DispatchQueue.main.async { 
        HUD.show(.labeledProgress(title: "Getting Records", subtitle: "\(province) - \(gender+Helpers.getAgeGroupFromAge(age: Int(ageGroup)!))")) 
       } 

       let requestUrl = "\(baseUrl)/Records.jsp" 
       let parameters = ["locale": "en", "province": province, "age": ageGroup, "gender": gender, "course": "*"] 

       Alamofire.request(requestUrl, method: .post, parameters: parameters).responseData(
        queue: processingQueue, 
        completionHandler: { response in 

         switch response.result { 
         case .success: 

          let recordArray = parseRecords(data: response.data!, province: province, ageGroup: ageGroup, gender: gender) 

         case .failure(let error): 
          DispatchQueue.main.async { 
           HUD.flash(.failure) 
          } 
          print("Alamofire request failed") 
          print(error) 
         } 
       } 
       ) 
      } 
     } 
    } 
} 

static func fetchLog() { 

    let requestUrl = "\(baseUrl)/ViewLog.jsp" 

    Alamofire.request(requestUrl).responseData(
     queue: processingQueue, 
     completionHandler: { response in 

      switch response.result { 
      case .success: 
       let log = parseLog(data: response.data!) 

      case .failure(let error): 
       DispatchQueue.main.async { 
        HUD.flash(.failure) 
       } 
       print("Alamofire request failed") 
      } 
     } 
    ) 
} 

// MARK: - Convenience structs 
struct MscRequest { 
    let profile: Bool 
    let log: Bool 
    let times: Bool 
    let records: Bool 
    let recordsToFetch: RecordsToFetch 
    let user: MscUser 

    let parentView: UITableViewController 
} 

:

여기에 지금까지 내 코드입니다 모든 HUD 업데이트는 (메인 스레드에서) 동시에 수행되고 백그라운드 페칭 및 파싱이 진행되는 동안 해지됩니다. 정확히 내가 무엇을하려고하는지 ...

Alamofire 매뉴얼 (completionHandler 부분을 생략 함)에서 HTML 요청 코드를 직접 시도했지만 여전히 얻을 수 있습니다. 동일한 결과 ...

는 또한 (예 :이 하나 : http://www.appcoda.com/grand-central-dispatch/를) 그랜드 센트럴 디스패치 튜토리얼을 살펴했지만, 나는 Alamofire를 사용할 때 참고로

... 정보를 적용하는 방법을 생각하지 않은 당시에 NSURLRequests 매뉴얼로 Objective-C에서이 작업을 할 수있었습니다. 나는이 오래된 응용 프로그램을 Swift 3으로 현대화하고 있으며 Alamofire를 시험해보아야한다고 생각했습니다.

나는 명백한 뭔가를 놓치고있는 것처럼 느껴지지 않을 수 있습니다 ... 어떤 팁?

+0

좋아,이 (http://stackoverflow.com/questions/36911192/how-to-load-view-after-alamofire-finished-its-job) 내가 필요하다고 생각하는 것에 훨씬 더 가깝지만 나는 ' 그것은 아직 작동하도록하는 방법을 찾지 못했습니다 ... –

+0

이 모양 (http://stackoverflow.com/questions/28634995/cha) in-multiple-alamofire-requests)도 도움이 될 수 있습니다 - PromiseKit이 아닌 경우 ... –

답변

2

좋아, 내가 DispatchGroup (스위프트 3, Alamofire 4.x의)

를 사용하여 원하는 것을 할 수있는 방법을 발견
func fetchData() { 
    let requestGroup = DispatchGroup() 

    //Need as many of these statements as you have Alamofire.requests 
    requestGroup.enter() 
    requestGroup.enter() 
    requestGroup.enter() 

    Alamofire.request("http://httpbin.org/get").responseData { response in 
     print("DEBUG: FIRST Request") 
     requestGroup.leave() 
    } 

    Alamofire.request("http://httpbin.org/get").responseData { response in 
     print("DEBUG: SECOND Request") 
     requestGroup.leave() 
    } 

    Alamofire.request("http://httpbin.org/get").responseData { response in 
     print("DEBUG: THIRD Request") 
     requestGroup.leave() 
    } 

    //This only gets executed once all the above are done 
    requestGroup.notify(queue: DispatchQueue.main, execute: { 
     // Hide HUD, refresh data, etc. 
     print("DEBUG: all Done") 
    }) 

} 
0

DownloadRequest를 사용하고 진행률을 사용해야합니다.

은 또한이 게시물을 살펴,이를 설명 :

Alamofire POST request with progress

+0

Humm ... 다운로드 진행 상황을 표시하고 싶지 않습니다. 새 요청이 시작될 때마다 hud를 업데이트하여 사용자에게 다운로드중인 내용을 알리려합니다. 개별 요청은 매우 빠르며, HTML 구문 분석을 사용하면 시간이 오래 걸릴 수 있습니다 ... –