Search code examples
swiftalamofiregrand-central-dispatchios-multithreadingdispatchgroup

How connect DispatchGroup and Executed Request Alamofire?


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?


Solution

  • 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")
            }
        }
    })