在Swift 3的每一步中,如何使用Alamofire执行顺序请求并更新progressHUD [英] How to perform sequential request with Alamofire and update a progressHUD at every step in Swift 3

查看:103
本文介绍了在Swift 3的每一步中,如何使用Alamofire执行顺序请求并更新progressHUD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,我要为此烦恼...

Ok, I am going nuts over this one...

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

I'm using Alamofire 4.x (Swift 3 and XCode 8.1). I need to fetch and parse several html requests from a site that requires authentication (no json API, unfortunately). The HTML is then parsed with Fuzi and this progress can take some time so I plan to use a ProgressHUD (PKHUD to be exact) to let users know about what is going on. I also need to grab some html that is not behind an authentication.

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

I created a struct and functions to handle the overall network process and to parse the data.

我设法执行了请求并获取了我需要的数据,但是我似乎无法弄清楚如何在正确的时间进行HUD更新。

I managed to perform the requests and grab the data I need but I can't seem to figure out how to make my HUD updates at the right time.

这是我到目前为止的代码:

Here is my code so far:

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并启动一系列这样的请求:

Under this setup, I would setup a MscRequest in a TableViewController and launch a series a requests like so:

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更新将同时完成(在主线程上)并最终在后台获取和解析仍在进行时被关闭。

With this setup, all the HUD updates are done at the same time (on the main thread) and end up being dismissed while the background fetching and parsing is still going on. Not exactly what I was going for...

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

I tried various iterations (with or without a custom queue), I also tried the HTML request code straight from Alamofire's manual (which omits the completionHandler part) but I still get the same results...

我也看过了Grand Central Dispatch教程(例如以下内容: http://www.appcoda.com/grand-central-dispatch/ ),但我没有没想到在使用Alamofire时如何应用信息...

I also had a look at Grand Central Dispatch tutorials (such as this one: http://www.appcoda.com/grand-central-dispatch/) but I haven't figured out how to apply info when using Alamofire...

值得注意的是,那时我设法在Objective-C中使用手动NSURLRequests进行了这项工作。我正在将该旧应用程序现代化为Swift 3,并认为我应该尝试一下Alamofire。

Of note, I managed to make this work in Objective-C with manual NSURLRequests back then. I'm modernizing this old application to Swift 3 and thought I should give Alamofire a try.

忍不住感觉自己似乎缺少了一些明显的东西……任何提示?

Can't help to feel like I am missing something obvious... Any tips?

推荐答案

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

Ok, I found a way to do what I want using a DispatchGroup (Swift 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")
    })

}

这篇关于在Swift 3的每一步中,如何使用Alamofire执行顺序请求并更新progressHUD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆