I have an async function that queries Parse. I need to wait until all objects from the Parse query have returned before calling my second function. The problem is, I'm using:
var group: dispatch_group_t = dispatch_group_create()
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { () -> Void in
asyncFunctionA() // this includes an async Parse query
}
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { () -> Void in
asyncFunctionB() // must be called when asyncFunctionA() has finished
}
...but, asyncFunctionB() is getting called before I even have any objects appended to my arrays in asyncFunctionA(). Isn't the point of using GCD notify to observe the completion of a prior function? Why isn't that working here?
Just like Parse employs the concept of completion block/closures, you need to do the same in your asyncFunctionA:
func asyncFunctionA(completionHandler: () -> ()) {
// your code to prepare the background request goes here, but the
// key is that in the background task's closure, you add a call to
// your `completionHandler` that we defined above, e.g.:
gameScore.saveInBackgroundWithBlock { success, error in
if (success) {
// The object has been saved.
} else {
// There was a problem, check error.description
}
completionHandler()
}
}
Then you could do something like your code snippet:
let group = dispatch_group_create()
dispatch_group_enter(group)
asyncFunctionA() {
dispatch_group_leave(group)
}
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
self.asyncFunctionB()
}
Note, if function A was really using Parse's asynchronous methods, then there's no need to use dispatch_async there. But if you need it for some reason, feel free to add that back in, but make sure the dispatch_group_enter occurs before to dispatch to some background thread.
Frankly, I'd only use groups if I had a whole bunch of items added to this group. If it really was just B waiting for single call to A, I'd retire the groups entirely and just do:
asyncFunctionA() {
self.asyncFunctionB()
}
Related
How can I prevent a block of code to be repeatedly accessed from the same thread?
Suppose, I have the next code:
func sendAnalytics() {
// some synchronous work
asyncTask() { _ in
completion()
}
}
I want to prevent any thread from accessing "// some synchronous work", before completion was called.
objc_sync_enter(self)
objc_sync_exit(self)
seem to only prevent accessing this code from multiple threads and don't save me from accessing this code from the single thread. Is there a way to do this correctly, without using custom solutions?
My repeatedly accessing, I mean calling this sendAnalytics from one thread multiple times. Suppose, I have a for, like this:
for i in 0...10 {
sendAnalytics()
}
Every next call won't be waiting for completion inside sendAnalytics get called (obvious). Is there a way to make the next calls wait, before completion fires? Or the whole way of thinking is wrong and I have to solve this problem higher, at the for body?
You can use a DispatchSemaphore to ensure that one call completes before the next can start
let semaphore = DispatchSemaphore(value:1)
func sendAnalytics() {
self.semaphore.wait()
// some synchronous work
asyncTask() { _ in
completion()
self.semaphore.signal()
}
}
The second call to sendAnalytics will block until the first asyncTask is complete. You should be careful not to block the main queue as that will cause your app to become non-responsive. It is probably safer to dispatch the sendAnalytics call onto its own serial dispatch queue to eliminate this risk:
let semaphore = DispatchSemaphore(value:1)
let analyticsQueue = DispatchQueue(label:"analyticsQueue")
func sendAnalytics() {
analyticsQueue.async {
self.semaphore.wait()
// some synchronous work
asyncTask() { _ in
completion()
self.semaphore.signal()
}
}
}
I have 2 dispatch_async() like this :
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
/* Code here */
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
/* Code here */
}
I want the second dispatch to wait until the first one finish his execution. how i can do that ?
Thank's in advance
I'll give a few solutions, in the order of increasing complexity:
1
The simplest way is to include both code blocks in the same async calls:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// code block 1
// code block 2
}
2
If you don't know precisely when they will run, for example, code block 1 is triggered when user presses a button and code block 2 is run when user presses another button, use a serial queue:
let serialQueue = dispatch_queue_create("mySerialQueue", DISPATCH_QUEUE_SERIAL)
dispatch_async(serialQueue) {
// code block 1
}
dispatch_async(serialQueue) {
// code block 2
}
3
If your code blocks run asynchronously, like first making a webservice call to authenticate, then making a second call to get the user's profile, you have to implement waiting:
let groupID = dispatch_group_create()
let task1 = session.dataTaskWithRequest(request1) { data, response, error in
// handle the response...
// Tell Grand Central Dispatch that the request is done
dispatch_group_leave(groupID)
}
let task2 = session.dataTaskWithRequest(request2) { data, response, error in
// handle the response...
}
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
dispatch_group_enter(groupID) // Tell GCD task1 is starting
task1.resume()
dispatch_group_wait(groupID, DISPATCH_TIME_FOREVER) // Wait until task1 is done
task2.resume()
}
4
For anything more complicated, I strongly suggest you learn NSOpereationQueue. There's a WWDC session on it
In Swift (that's Swift) there are a number of ways to handle asynchronous,
Say you have a loop like this - it's calling a parse cloud code call which goes to background anyway.
public func runImages()
{
print("test begins...")
for i in 1...3
{
print("Tick tock tick tock ..\(i)")
PFCloud.callFunctionInBackground("blah", withParameters:["bla":i,"bla":"bla] )
{
(response: AnyObject?, error: NSError?) -> Void in
print(".. done! Now go again...")
if let rr = response as? String { print(rr) }
if let err = error { print(err.domain) }
}
}
}
How to make that wait for the end of each PFCloud call?
Really is just an ordinary flag best, or? (Note that (a) I can't get a flag to work in Swift and (b) as Paul points out you're blocking the UI!!)
What is the "Swift way" in the context you see here? I feel it would be very inelegant to use a recursive pattern here, for example.
If you want the three calls to execute serially then you can use a serial dispatch queue and a dispatch_barrier_async to do something when all three are finished -
let dispatchQueue=dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL)
for i in 1...3 {
dispatch_async(dispatchQueue, { () -> Void in
print("i=\(i)")
let result = PFCloud.callFunction("blah", withParameters:["bla":i,"bla":"bla] )
})
}
dispatch_barrier_async(dispatchQueue, { () -> Void in
print("really done")
})
print(" done")
In order for this to work with your Parse function you need to use the synchronous cloud code call, not an asynchronous. And if you update UI in the dispatch_barrier_async closure you would need to dispatch that on the main queue.
ok I am updating this question but left the old one there.
So I have an array that stores the data for different views in a uipageviewcontroller. I need to grab image data in the background. I don't understand how to code this though within an asynchronous task.
Heres the code for the task:
let queue = NSOperationQueue()
queue.addOperationWithBlock() {
// do something in the background
println("background")
self.cards[newIndex].loadImag()
var cardimages = self.cards[newIndex].images
NSOperationQueue.mainQueue().addOperationWithBlock() {
// when done, update your UI and/or model on the main queue
println("update ui")
self.cards[newIndex].images = cardimages
}
}
this is what the .loadImag() function looks like:
func loadImag(){
println("images= \(self.images)")
if self.
location_id != nil && (self.images == nil) {
println("before api call loc_id= \(self.location_id)")
ApiWrapper.getPictures(self.location_id!, completionHandler: self.imagesCallback)
}
}
}
and this is self.imagesCallback code:
private func imagesCallback(cardImagesArray: [CardImage]){
println("images callback id= \(self.location_id)")
self.images = cardImagesArray
}
problem is I am not sure how to put this code inside of the operation cue since the function must have a callback. How can I get the operation queue working so that it updates the self.card array in the uipageviewcontroller?
OLD QUESTION_________________:
So I have this line of code I need to run concurrently in a different thread than the main thread. When I add it to the main queue like so:
var queue = dispatch_get_main_queue()
dispatch_async(queue, {
self.cards[newIndex].loadImage()
})
doing this it works fine but doesn't seem to run concurrently. When I change the queue to concurrent like this:
dispatch_async(DISPATCH_QUEUE_CONCURRENT, {
self.cards[newIndex].loadImage()
})
The app crashes saying "EXC_BAD_ACCESS". What am I doing wrong here? Also when I run the self.cards[newIndex].loadImage() function in a different concurrent thread will this update the values in the main thread?
you shouldn't use GCD unless you want to explicitly use functionality which is only available on GCD. For your case it is more beneficial (and cleaner in code) to use NSOperationQueue. NSOperationQueue uses GCD in the background and is more secure (less ways to mess up)
let queue = NSOperationQueue()
queue.addOperationWithBlock() {
// do something in the background
NSOperationQueue.mainQueue().addOperationWithBlock() {
// when done, update your UI and/or model on the main queue
}
}
You can also read through the Apple Concurrency Programming Guide
The guide is using examples with Objective-C but API is basically the same for Swift.
It also might look strange but with the addOperationWithBlock() I used something called "trailing closure" you can read here about it
Can you paste the whole code so we can see what are you doing?
Below is very basic code snippet. This is basically how concurrency works in Swift.
let qos = Int(QOS_CLASS_USER_INITIATED.value)
dispatch_async(dispatch_get_global_queue(qos, 0), { () -> Void in
// Put your code here to work in the background
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// Put your code here when the process is done and hand over to the main thread.
// Ex. self.cards[newIndex].loadImage()
})
})
You need to use dispatch_get_global_queue . Try something like:
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue, {self.cards[newIndex].loadImage()})
dispatch_get_main_queue(), as you were trying, runs on the UI/main thread, which is why you saw the behavior you did.
To answer the second part of your question, If loadImage() is modifying the UI, you don't want to do that from a background thread. It must be done from the main/UI thread. A typical idiom would be, from the main thread do:
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue, {
<code to load/prepare images>
dispatch_async(dispatch_get_main_queue(), {
<code to update UI elements>
})
})
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
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.
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
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 ;)