In Xcode 9 / Swift 4 using Google APIs Client Library for Objective-C for REST: why does service.executeQuery return thread completion notification before the thread completes? I have been trying various ways but I am stuck with the following code where the notification is returned before the thread completes. See below the code, the actual output and what I would expect to see (notification comes once the thread has complete). What am I doing wrong? Thanks
func myFunctionTest () {
let workItem = DispatchWorkItem {
self.service.executeQuery(query,
delegate: self,
didFinish: #selector(self.displayResultWithTicket2b(ticket:finishedWithObject:error:))
)
}
let group = DispatchGroup()
group.enter()
group.notify(queue: service.callbackQueue) {
print("************************** NOTIFY MAIN THREAD *************************************")
}
service.callbackQueue.async(group: group) {
workItem.perform()
}
group.leave()
}
@objc func displayResultWithTicket2b(ticket : GTLRServiceTicket,
finishedWithObject messagesResponse : GTLRGmail_ListMessagesResponse,
error : NSError?) {
//some code to run here
print("************************** 02.displayResultWithTicket2b ***************************")
}
Output
************************** NOTIFY MAIN THREAD ************************************* ************************** 02.displayResultWithTicket2b ***************************
What I would expect = Thread notification comes when thread has completed
************************** 02.displayResultWithTicket2b *************************** ************************** NOTIFY MAIN THREAD *************************************
The problem is that you're dealing with an asynchronous API and you're calling
leavewhen you're done submitting the request. Theleave()call has to be inside the completion handler or selector method of yourexecuteQuerycall. If you're going to stick with this selector based approach, you're going to have to save the dispatch group in some property and then havedisplayResultWithTicket2bcallleave.It would be much easier if you used the block/closure completion handler based rendition of the
executeQueryAPI, instead of the selector-based API. Then you could just move theleaveinto the block/closure completion handler and you'd be done. If you use the block based implementation, not only does it eliminate the need to save the dispatch group in some property, but it probably eliminates the need for the group at all.Also, the callback queue presumably isn't designed for you to add your own tasks. It's a queue that the library will use the for its callbacks (the queue on which completion blocks and/or delegate methods will be run). Just call
executeQueryand the library takes care of running the callbacks on that queue. And noDispatchWorkItemis needed:The only time I'd use a dispatch group would be if I was performing a series of queries and needed to know when they were all done: