Filipe Louro
Filipe Louro

Reputation: 87

Swift Serial Dispatch Block only finish after delegate

this is a hard one to explain. I am creating a serial queue for handling some work in my app. Imagine that i do something like this:

dispatch_async(myQueue, { () -> Void in
            self.SendSMS();
            });

dispatch_async(myQueue, { () -> Void in
            self.SendEmail();
            });

Now what i would like to do is to only call the self.SendEmail after a delegate(SendSMS delegate) finishes its work.

Is there a simple way to do this?

Many thanks

Upvotes: 1

Views: 1775

Answers (3)

dimpiax
dimpiax

Reputation: 12687

Yes, you can do it, in next steps:

// create tasks group handle
let taskGroup = dispatch_group_create()
let mainQueue = dispatch_get_main_queue()

// write your blocks in needed order
dispatch_group_async(taskGroup, mainQueue) { [weak self] in
    // execute your code
    // don't forget to use self with optional, i.e.: self!.property or function
    self!.SendSMS()
}

dispatch_group_async(taskGroup, mainQueue) { [weak self] in
    self!.SendEmail()
}

// and of course you need to catch completion of this task group
dispatch_group_notify(taskGroup, mainQueue) {
    println("All work is done, milord!")
}

UPD. The solution above is about asynchronous execution without order, as named and one of two can be completed earlier than declared order. You need to use dependencies as solution of continuously execution. I'm talking about ordering in multithreading, not about completion closures or executor pattern. Notice, that there're more than one case to do this. One of them – below:

let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue) {
    dispatch_sync(queue) {[weak self] in
        self?.SendSMS()
    }

    dispatch_sync(queue) {[weak self] in
        self?.SendEmail()

        // here you need to call your completion of success function in main thread
    }
}

Be aware, that code in your functions must exists in the same queue and use synchronous method for server requests. But this is another story ;)

Upvotes: -1

Rob
Rob

Reputation: 437947

Assuming that SendSMS is an asynchronous method, I'd advise changing SendSMS to take a completion handler closure:

// define property to hold closure

var smsCompletionHandler: (()->())?

// when you initiate the process, squirrel away the completion handler

func sendSMSWithCompletion(completion: (()->())?) {
    smsCompletionHandler = completion

    // initiate SMS
}

// when the SMS delegate method is called, call that completion closure

func messageComposeViewController(controller: MFMessageComposeViewController!, didFinishWithResult result: MessageComposeResult) {
    // do whatever you want when done

    // finally, call completion handler and then release it

    smsCompletionHandler?()
    smsCompletionHandler = nil
}

Thus, you'd call it like so, putting the sendEmail inside the completion closure of sendSMS:

self.sendSMSWithCompletion() {
    self.sendEmail()
}

I don't know what your sendSMS and sendEmail are doing, but if you're calling the MessageUI framework, you'd generally do that on the main queue. But if you really need to do the above on your dedicated queue, then feel free to dispatch it there. But hopefully this illustrates the concept: (a) supply completion handler closure; (b) save it so your delegate can call it; and (c) when delegate is called, use that closure property and then reset it.

Upvotes: 2

Filipe Louro
Filipe Louro

Reputation: 87

one way to do it, and it works is to put:

dispatch_async(myQueue, { () -> Void in
        self.SendEmail();
        });

at the end of the delegate. But i dont know if this is the only way to do this.

Cheers

Upvotes: 0

Related Questions