I have an iOS application that runs multiple classes(every class in a separate thread) and I want to get a notification when all the class finishes their run.
So I have a BaseClass:
class BaseClass {
var completeState: CompleteState
init(completeState: CompleteState) {
self.completeState = completeState
self.completeState.dispatch.enter()
}
func start() { }
}
And this is the CompleteState Class:
class CompleteState {
let userId:String
let dispatch = DispatchGroup()
init(userId:String) {
self.userId = userId
dispatch.notify(queue: DispatchQueue.main) {
print("Finish load all data")
}
}
}
And I have multiple classes that inherit from BaseClass
, and all of them are in this form:
class ExampleClass1: BaseClass {
override func start() {
DispatchQueue.global().async {
print("ExampleClass1 - Start running")
//DOING SOME CALCULATIONS
print("ExampleClass1 - Finish running")
self.completeState.dispatch.leave()
}
}
}
This is the code that runs all of this:
public class RunAll {
let completeState: CompleteState
let classArray: [BaseClass]
public init(userId: String) {
self.completeState = CompleteState(userId: userId)
classArray = [ExampleClass1(completeState: completeState),
ExampleClass2(completeState: completeState),
ExampleClass3(completeState: completeState),
ExampleClass4(completeState: completeState),
ExampleClass5(completeState: completeState),
ExampleClass6(completeState: completeState),
ExampleClass7(completeState: completeState),
ExampleClass8(completeState: completeState),
ExampleClass9(completeState: completeState)]
startClasses()
}
private func startClasses() {
for foo in classArray {
foo.start()
}
}
}
And the problem is that I get dispatch.notify
called before all the classes finish their work, any idea what is the problem?
CodePudding user response:
The documentation for notify
states:
This function schedules a notification block to be submitted to the specified queue when all blocks associated with the dispatch group have completed. If the group is empty (no block objects are associated with the dispatch group), the notification block object is submitted immediately. When the notification block is submitted, the group is empty.
You are calling dispatch.notify()
in your CompleteState
init
. At the time you are calling notify
, the dispatch group is empty, because you haven't yet created a BaseClass
subclass let along called start
, which is where the dispatch group is entered.
Because you call notify
when the dispatch group is empty, the block is submitted immediately.
It may be worth looking into OperationQueue
, but if you want to use what you have you can split the notify
out from the init
:
lass CompleteState {
let userId:String
let dispatch = DispatchGroup()
init(userId:String) {
self.userId = userId
}
func registerCompletionBlock(handler: @escaping () -> Void) {
self.dispatch.notify(queue: DispatchQueue.main, execute: handler)
}
}
You would then provide the completion block after you call startClasses
public init(userId: String) {
self.completeState = CompleteState(userId: userId)
classArray = [ExampleClass1(completeState: completeState),
ExampleClass2(completeState: completeState),
ExampleClass3(completeState: completeState),
ExampleClass4(completeState: completeState),
ExampleClass5(completeState: completeState),
ExampleClass6(completeState: completeState),
ExampleClass7(completeState: completeState),
ExampleClass8(completeState: completeState),
ExampleClass9(completeState: completeState)]
startClasses()
self.completeState.registerCompletionBlockHandler {
print("Finish load all data")
}
}