1

I have two functions: func Females_NonChat() and func males_NonChat() I want to wait for both of them to finish before executing the print statement in viewdidload. Do I need another completion handler to accomplish that?

Those functions used are firebase completion handlers for requesting information from the online database...

override func viewDidLoad() {
    super.viewDidLoad()
    func Females_NonChat()
    func males_NonChat()

    print("finished executing both asynchronous functions")
}

func Females_NonChat(){
    Anon_Ref.child("Chatting").child("female").observeSingleEventOfType(.Value, withBlock: {(snapshot) in
        if let FemInChatting = snapshot.value as? [String : String] {
            print("executing")
        }
    })
}

func males_NonChat(){
    Anon_Ref.child("Chatting").child("male").observeSingleEventOfType(.Value, withBlock: {(snapshot) in
        print("executing")
    })
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
slimboy
  • 1,633
  • 2
  • 22
  • 45
  • 4
    What the heck is `func Females_NonChat(); func males_NonChat()` in your `viewDidLoad`? That isn't even legal Swift. Provide code that _compiles_ (if you can). – matt Aug 26 '16 at 22:05
  • I'd say this is a total duplicate of http://stackoverflow.com/questions/11909629/waiting-until-two-async-blocks-are-executed-before-starting-another-block?rq=1, which appears first in the Related list. Did you even try searching before asking? – matt Aug 26 '16 at 22:06
  • @matt as far as I know we can use nested functions in Swift, so function can contain another function inside, no? – Evgeny Karkan Aug 26 '16 at 22:09
  • @EvgenyKarkan What are you saying? Those are not nested functions. They are neither function declarations nor function calls. They are illegal syntax. If they were _calls_ they would not say `func`. If they were _declarations_ they would have _bodies_ (curly braces). – matt Aug 26 '16 at 23:55

2 Answers2

6

Generally you'd use a dispatch group, enter the group before each asynchronous method, leave the group upon completion of each asynchronous method, and then set up a group notification when all "enter" calls are matched by corresponding "leave" calls:

override func viewDidLoad() {
    super.viewDidLoad()

    let group = dispatch_group_create()

    dispatch_group_enter(group)
    Females_NonChat() {
        dispatch_group_leave(group)
    }

    dispatch_group_enter(group)
    males_NonChat() {
        dispatch_group_leave(group)
    }

    dispatch_group_notify(group, dispatch_get_main_queue()) { 
        print("finished executing both asynchronous functions")
    }
}

func Females_NonChat(completionHandler: () -> ()) {
    Anon_Ref.child("Chatting").child("female").observeSingleEventOfType(.Value) { snapshot in
        if let FemInChatting = snapshot.value as? [String : String] {
            print("executing")
        }
        completionHandler()
    }
}

func males_NonChat(completionHandler: () -> ()) {
    Anon_Ref.child("Chatting").child("male").observeSingleEventOfType(.Value) { snapshot in
        print("executing")
        completionHandler()
    }
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

Here's an example that executes two async methods and prints when both are finished.

Try copying this code into a Swift Playground and running it.

import Foundation

func doTwoThings() {
    var thing1Done: Bool = false
    var thing2Done: Bool = false

    func done() {
        if thing1Done && thing2Done {
            print("Both things done! at \(getTime())")
        }
    }

    doThing1(completionHandler: {
        thing1Done = true
        done()
    })

    doThing2(completionHandler: {
        thing2Done = true
        done()
    })
}

func doThing1(completionHandler: @escaping () -> Void) {
    print("Starting Thing 1 at \(getTime())")
    Timer.scheduledTimer(withTimeInterval: 3, repeats: false, block: {_ in
        print("Done with Thing 1 at \(getTime())")
        return completionHandler()
    })
}

func doThing2(completionHandler: @escaping () -> Void) {
    print("Starting Thing 2 at \(getTime())")
    Timer.scheduledTimer(withTimeInterval: 5, repeats: false, block: {_ in
        print("Done with Thing 2 at \(getTime())")
        return completionHandler()
    })
}

func getTime() -> String {
    let date = Date()
    let calendar = Calendar.current
    let hour = calendar.component(.hour, from: date)
    let minute = calendar.component(.minute, from: date)
    let second = calendar.component(.second, from: date)
    return "\(hour):\(minute):\(second)"
}

doTwoThings()

Output:

Starting Thing 1 at 11:48:51
Starting Thing 2 at 11:48:51
Done with Thing 1 at 11:48:54
Done with Thing 2 at 11:48:56
Both things done! at 11:48:56
Derek Soike
  • 11,238
  • 3
  • 79
  • 74