使用DispatchGroup进行同步Alamofire请求

时间:2017-12-08 16:20:18

标签: ios swift loops alamofire dispatch

我需要等到Alamofire请求完成获取数据。 (错误或值)。我在另一个函数的for循环中调用Alamofire函数,以便Alamofire请求应该在第二个for循环调用之前完成。例如;第一个循环 - >第一次请求 - >第二个循环 - >第二个请求......等等。现在它首先循环 - >第二个循环 - >在所有循环完成后,请求响应正在转变。

请求功能:

 func like(sender_id: String, completion: @escaping (String?) -> ()){
    let group = DispatchGroup()
    if let key = api_key{
        let headers: HTTPHeaders = [
            "X-Auth-Token": key,
            "Accept": "application/json"
        ]
        group.enter()
        Alamofire.request(baseUrl + likeURL + sender_id, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).validate()
            .responseJSON { (response) -> Void in
                guard response.result.isSuccess else {
                    print("Error while doing : \(response.result.error)")
                    completion(nil)
                    group.leave()
                    return
                }
                if let error = response.error{
                    completion(nil)
                    group.leave()
                    print("Error Occured with Request: \(error)")
                }
                if let jsonData = response.data{
                    let json = JSON(data: jsonData)
                    print(json)
                    group.leave()
                    if let matched = json["match"].bool{
                        completion(matched.description)
                        print("Liked!: \(matched)")
                        if(matched){
                        }
                    }else{
                        group.leave()
                        "There is an error with JSON"
                    }
                }}
    }
}

我打电话的地方:

 func like_all(completion: @escaping() -> ()){
    for user in SharedUsers.sharedUser.users{
        if let id = user.id{
            Network.sharedInstance.like(sender_id: id) { result in
                print(result)
            }
        }
        else{
            continue
        }
    }
    completion()
}

2 个答案:

答案 0 :(得分:1)

您正在使用调度组,显然是为了在函数结束时等待组。但是你并没有等待它,所以你没有得到你想要的同步行为。

但那很好,因为如果您在主线程上为该组(或信号量,实现此行为的另一种模式)wait,则不仅会阻塞主线程(导致可怕的用户体验以及让你的应用程序被监视程序进程杀死的风险),你会因为responseJSON使用主队列完成处理程序而导致死锁。因此,在您的调度组/信号量上添加wait()调用之前,请确保将此整个for循环异步调度到某个后台线程。这可以避免阻塞主线程并消除死锁风险。

但是这整个模式存在根本缺陷,因为你真的不应该使用调度组或信号量来使它同步。这引出了一些问题:

第一个问题是你想让它同步的原因。网络请求具有固有的延迟,因此您执行它们的序列将非常缓慢。如果你绝对必须,只做这个请求序列(例如,因为它需要来自先前请求的响应的某些请求,所以不能形成每个请求)。但这似乎并非如此。那么为什么不需要这个过程呢。

但是让我们假设你必须按顺序执行这些(这里不是真的,我可以告诉你,但让我们把它弄清楚)。然后有两种模式可以连续而不是同时执行一系列请求:

  • 您可以完全丢失此for循环,只需拥有一个发送第n个请求的例程,并在其完成处理程序中发送请求n + 1。这完全消除了调度组/信号量阻塞线程的需要。

  • 或者您可以将其包含在操作中(例如https://stackoverflow.com/a/27022598/1271826)并使用操作队列。

答案 1 :(得分:0)

每当Alamofire返回值时,我通过调用类似函数的索引+ 1来解决它。我也在获取请求的完成部分调用函数。

以下是代码:

    @objc func action(_ sender: LGButton) {
        sender.titleString = "Started to Like :)"
        Network.sharedInstance.get_rec(completion: { (result) in
            if(result != nil)
            {
                Network.sharedInstance.like(sender: 0, completion: { (result) in
                    //print(result)
                })
            }
        })
}

喜欢功能:

 func like(sender: Int, completion: @escaping (String?) -> ()){
    if let key = api_key{
        let headers: HTTPHeaders = [
            "X-Auth-Token": key,
            "Accept": "application/json"
        ]
        print(sender)
        print(SharedUsers.sharedUser.users.count)
        if(sender < SharedUsers.sharedUser.users.count){
            if let user_id = SharedUsers.sharedUser.users[sender].id{
                Alamofire.request(baseUrl + likeURL + user_id, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).validate()
                    .responseJSON { (response) -> Void in
                        guard response.result.isSuccess else {
                            print("Error while doing : \(response.result.error)")
                            completion(nil)
                            return
                        }
                        if let error = response.error{
                            completion(nil)
                            print("Error Occured with Request: \(error)")
                        }
                        if let jsonData = response.data{
                            let json = JSON(data: jsonData)
                            if let matched = json["match"].bool{
                                completion(matched.description)
                                print("Liked!: \(matched)")
                                if(sender <= SharedUsers.sharedUser.users.count){
                                    self.like(sender: sender + 1, completion: {result in
                                        //print(result)
                                    })
                                }else{
                                    return
                                }
                                if(matched){
                                }
                            }else{
                                "There is an error with JSON"
                            }}}
            }else{return}
        }}}