Swift3 如何在Swift 3中的每一步使用Alamofire执行顺序请求并更新progressHUD

Swift3 如何在Swift 3中的每一步使用Alamofire执行顺序请求并更新progressHUD,swift3,grand-central-dispatch,alamofire,xcode8.1,Swift3,Grand Central Dispatch,Alamofire,Xcode8.1,好吧,我为这件事发疯了 我使用的是Alamofire4.x(Swift 3和XCode 8.1)。我需要从一个需要身份验证的站点获取和解析几个html请求(不幸的是,没有JSONAPI)。然后用Fuzi解析HTML,这个过程可能需要一些时间,所以我计划使用ProgressHUD(确切地说是PKHUD)让用户知道正在发生什么。我还需要获取一些不在身份验证后面的html 我创建了一个结构和函数来处理整个网络过程并解析数据 我设法执行了请求并获取了所需的数据,但我似乎不知道如何在正确的时间更新HUD

好吧,我为这件事发疯了

我使用的是Alamofire4.x(Swift 3和XCode 8.1)。我需要从一个需要身份验证的站点获取和解析几个html请求(不幸的是,没有JSONAPI)。然后用Fuzi解析HTML,这个过程可能需要一些时间,所以我计划使用ProgressHUD(确切地说是PKHUD)让用户知道正在发生什么。我还需要获取一些不在身份验证后面的html

我创建了一个结构和函数来处理整个网络过程并解析数据

我设法执行了请求并获取了所需的数据,但我似乎不知道如何在正确的时间更新HUD

以下是我目前的代码:

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
}
在此设置下,我将在TableViewController中设置MscRequest,并启动一系列a请求,如下所示:

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)
通过此设置,所有HUD更新都会同时完成(在主线程上),并在后台获取和解析仍在进行时终止。不完全是我想要的

我尝试了各种迭代(有或没有自定义队列),我也直接从Alamofire的手册中尝试了HTML请求代码(省略了completionHandler部分),但仍然得到了相同的结果

我也看过GrandCentralDispatch教程(比如这篇:),但我还没有弄明白如何在使用Alamofire时应用信息

值得注意的是,我在Objective-C中通过手动请求实现了这一点。我正在将这个旧的应用程序升级到Swift 3,我想我应该试试Alamofire


我忍不住觉得我错过了一些明显的东西。。。有什么建议吗

您必须使用DownloadRequest和progress

再看看这篇文章,它解释道:


好的,我找到了一种使用DispatchGroup(Swift 3,Alamofire 4.x)做我想做的事情的方法


哼。。。我不想显示下载进度。我想在每个新请求开始时更新hud,让用户知道正在下载的内容。单个请求非常快,html解析可能需要一些时间…好的,这个()非常接近我认为需要的内容,但我还没有弄清楚如何使其工作…看起来这个()可能也有帮助-如果没有,也许PromiseKit。。。
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")
    })

}