Search code examples
swiftswift3grand-central-dispatchweak-referencesblockingqueue

DispatchGroup [weak self] handling in nested notify


I have two asynchronous functions. I need to run second function based on first's output and run third function after second is complete. I did it like this. Is it correct way to handle serialization? And how to handle weak self reference?

let dispatchGroup = DispatchGroup()

dispatchGroup.enter()
function1() // async completion contains leave()

dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
    guard let strongSelf = self else {return}
    strongSelf.dispatchGroup.enter()    
    strongSelf.function2() // Also async, dependent on the result of function1. contains leave()

    strongSelf.dispatchGroup.notify(queue: DispatchQueue.main) {
        strongSelf????.function3()
        print("results of function1 and function2")
        // I must wait to finish first two tasks in order, in other words serial queue
    }
}

Solution

  • 1) Correct way to: call the method after the previous one has completed

    class SomeAsyncType {
    
        typealias SomeResultType = String
    
        func async(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
            self.asyncfunctionA(someDate, completion: completion)
        }
    
        private func asyncfunctionA(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
            DispatchQueue.main.async { [weak self] in
                sleep(1)
                print("ResultA")
                self?.asyncfunctionB("ResultA", completion: completion)
            }
        }
    
        private func asyncfunctionB(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
            DispatchQueue.main.async { [weak self] in
                sleep(2)
                print("ResultB")
                self?.asyncfunctionC("ResultB", completion: completion)
            }
        }
    
        private func asyncfunctionC(_ someDate: Any, completion: @escaping (SomeResultType) -> Void) {
           DispatchQueue.main.async {
                sleep(3)
                print("ResultC")
                completion("🙈🙊🙉")
                print("All completed")
            }
        }
    }
    

    usage:

    let test = SomeAsyncType() // hold reference 
    test.async("noDate") { result in
        print(result)
    }
    

    console:

    ResultA
    ResultB
    ResultC
    🙈🙊🙉
    All completed
    

    2) how to handle weak self reference?

    This is new scope then you can use [weak self] again

    dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
        guard let strongSelf = self else {return}
        strongSelf.dispatchGroup.enter()
        strongSelf.function2() // Also async, dependent on the result of function1. contains leave()
    
        strongSelf.dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
            guard let strongSelf = self else {return}
            strongSelf.function3()
            print("results of function1 and function2")
        }
    }