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