Using DispatchGroup() in Swift 3 to perform a task?
Solution 1
With hint provided in the comment and solution found here: from @vadian, since I am only performing one task, I used a async completion handler:
Second Class:
func checkSpeed(completion: @escaping () -> ())
{
// call other functions and perform task to download file from link
// print out speed of download
nMbps = speedOfDownload
completion()
}
First Class:
let check: SecondClass = SecondClass()
check.checkSpeed {
print("speed = \(check.nMbps)")
}
Now checkSpeed
will complete first and speed
is assigned the appropriate value.
Solution 2
You need to call DispatchGroup.leave()
when the entered task has completed. So, in your code, myGroup.leave()
needs be placed at the end of the completion handler inside your checkSpeed()
method.
You may need to modify your code like this:
func checkSpeed(in myGroup: DispatchGroup) {
//...
...downLoadTask... {...its completion handler... in
//...
// print out speed of download
nMbps = speedOfDownload
myGroup.leave() //<- This needs to be placed at the end of the completion handler
}
//You should not place any code after invoking asynchronous task.
}
And use it as:
myGroup.enter()
check.checkSpeed(in: myGroup)
myGroup.notify(queue: DispatchQueue.main, execute: {
print("Finished all requests.")
print("speed = \(check.nMbps)")
})
But, as noted in vadian's comment or Pangu's answer, you usually do not use DispatchGroup
for a single asynchronous task.
ADDITION
I need to say, I strongly recommend completion handler pattern shown in Pangu's answer. It's a more general way to handle asynchronous tasks.
If you have modified your checkSpeed()
to checkSpeed(completion:)
as suggested, you can easily experiment DispatchGroup
like this:
let myGroup = DispatchGroup()
let check: SecondClass = SecondClass()
let anotherTask: ThirdClass = ThirdClass()
myGroup.enter() //for `checkSpeed`
myGroup.enter() //for `doAnotherAsync`
check.checkSpeed {
myGroup.leave()
}
anotherTask.doAnotherAsync {
myGroup.leave()
}
myGroup.notify(queue: DispatchQueue.main) {
print("Finished all requests.")
print("speed = \(check.nMbps)")
}
Related videos on Youtube
Pangu
Updated on June 04, 2022Comments
-
Pangu almost 2 years
With Swift 3, using GCD has changed to
DispatchGroup()
, and I'm trying to learn to use it in my code.Currently I have a function in another class that attempts to download a file and output its speed. I like to have that function finish first because I assign its speed to a
var
that I will be using in the first class to perform other tasks that is dependent upon thatvar
.It goes something like this:
Second class:
func checkSpeed() { // call other functions and perform task to download file from link // print out speed of download nMbps = speedOfDownload }
First Class:
let myGroup = DispatchGroup() let check: SecondClass = SecondClass() myGroup.enter() check.checkSpeed() myGroup.leave() myGroup.notify(queue: DispatchQueue.main, execute: { print("Finished all requests.") print("speed = \(check.nMbps)") })
The problem is
Finish all requests
gets output first, thus returningnil
forspeed
, then afterwardscheckSpeed
finishes and outputs the correct download speed.I believe I'm doing this wrong, but I'm not sure?
How can I ensure that
speed
obtains the correct value after the completion ofcheckSpeed
in my first class?The details of
checkSpeed
is exactly the same asconnectedToNetwork
from GitHub: connectedness.swift-
vadian over 7 yearsIf you are talking about one file you need an asynchronous completion handler rather than a group.
-
-
Pangu over 7 yearsOOPer: apologize GCD has already confused me from the beginning, but without going into too much details,
DispatchGroup
group is mainly used for..?...groups of asynchronous tasks? -
OOPer over 7 years
DispatchGroup
is mainly used for groups of asynchronous tasks? Right.DispatchGroup
is intended to use with multiple asynchronous tasks, to expect to be notified when all the tasks in the group has finished. When all the tasks entered in the group have calledDispatchGroup.leave()
, the closure specified withnotify(queue:execute:)
is invoked.