Home > database >  How connect DispatchGroup and Executed Request Alamofire?
How connect DispatchGroup and Executed Request Alamofire?

Time:03-18

I have a simple task with threads, but what seems to help everyone else, doesn’t work for me and I don’t understand why.

This is my button processing:

AnyButton(action: {
                    if isPhoneMode {
                        
                        print("starting long running tasks")
                        let group = DispatchGroup()
                        group.enter()
                        DispatchQueue.global().async {
                            urlService.loginRequest(login: " \(countryCode)\(phoneNumber)", password: password, completion: {
                                print("print in complition")
                            })
                            print("long task done!")
                            group.leave()
                        }
                        group.notify(queue: DispatchQueue.global()) {
                            print("all tasks done!")
                        }
                        
                    }

This is loginRequest:

func loginRequest(login: String, password: String, completion: @escaping () -> Void) {
    let parameters: Parameters = [
        "language": "EN",
        "password": password,
        "username": login
    ]
    let url = "someURL"
    let authRequest = AF.request(url,
                                 method: .post,
                                 parameters: parameters,
                                 encoding: JSONEncoding.default)
    authRequest.responseString { response in
        switch response.result {
        case .success(let value):
            let responseArr = value.components(separatedBy: "\u{0022}")
            if responseArr[11] == "ACTIVE" {
                self.loginStatus = .correctLogin
                print("correct login!")
            }
        case .failure(let error):
            print("Error: \(String(describing: error))")
            self.loginStatus = .requestFail
        }
    }
    completion()
}

group.notify can't track correctly my request. Correct login always last in console: Why so?

starting long running tasks 
print in complition 
long task done! 
all tasks done! 
correct login!

I want it to be before “long task done”. How can i do this?

CodePudding user response:

First of all you are misusing DispatchGroup. As the name group implies it's for multiple tasks, but you are performing only one task.

The reason for the unexpected behavior is that the leave command is outside of the completion closure. So leave will be executed immediately and the group calls notify

This does what you expect without DispatchGroup

AnyButton(action: {

    if isPhoneMode {
        
        print("starting long running tasks") // actually one task
        DispatchQueue.global().async {
            urlService.loginRequest(login: " \(countryCode)\(phoneNumber)", password: password, completion: {
                DispatchQueue.main.async {
                    print("print in completion")
                    print("long task done!")
                }
            })
        }
    }

CodePudding user response:

You ask:

“Correct login” always last in console: Why so?

Because your call to your completion handler is not in the right place. E.g.

func loginRequest(login: String, password: String, completion: @escaping () -> Void) {
    …

    authRequest.responseString { response in
        switch response.result { … }

        completion()                       // Move `completion` here
    }

    // completion()                        // It should not be here
}

You have a similar problem in your dispatch group, namely that leave belongs inside the completion handler:

AnyButton(action: {
    if isPhoneMode {
        print("starting long running tasks")
        
        let group = DispatchGroup()
        group.enter()
        
        urlService.loginRequest(login: " \(countryCode)\(phoneNumber)", password: password) {
            print("print in completion")
            
            group.leave()                 // Move `leave` here
        }
        
        print("long task done!")
        
        // group.leave()                  // not here
        
        group.notify(queue: DispatchQueue.global()) {
            print("all tasks done!")
        }
    }
})

Note, I’ve removed the redundant dispatch to the global queue (as loginRequest already runs asynchronously).

But since you have a single task, the dispatch group is redundant, too. You only use groups if you have multiple tasks for which you need to be notified when they are complete. In this case, though, it is syntactic noise. So, this can be simplified further, to:

AnyButton(action: {
    if isPhoneMode {
        print("starting long running tasks")
        
        urlService.loginRequest(login: " \(countryCode)\(phoneNumber)", password: password) {
            print("print in completion")
        }
    }
})
  • Related