I've seen some related questions but none seem to answer this case. I want to write a method that will do some work in the background. I need this method to call a completion callback on the same thread / queue used for the original method call.
- (void)someMethod:(void (^)(BOOL result))completionHandler {
dispatch_queue_t current_queue = // ???
// some setup code here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL ok = // some result
// do some long running processing here
dispatch_async(current_queue, ^{
completionHandler(ok);
});
});
What magic incantation is needed here so the completion handler is called on the same queue or thread as the call to sameMethod? I don't want to assume the main thread. And of course dispatch_get_current_queue is not to be used.
If you look through the Apple docs, there appear to be two patterns.
If it is assumed that the completion handler is to be run on the main thread, then no queue needs to be provided. An example would be UIView's animations methods:
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
Otherwise, the API usually asks the caller to provide a queue:
[foo doSomethingWithCompletion:completion targetQueue:yourQueue];
My suggestion is to follow this pattern. If it is unclear which queue the completion handler should be called, the caller should supply it explicitly as a parameter.
You can't really use queues for this because, aside from the main queue, none of them are guaranteed to be running on any particular thread. Instead, you will have to get the thread and execute your block directly there.
Adapting from Mike Ash's Block Additions:
// The last public superclass of Blocks is NSObject
#implementation NSObject (rmaddy_CompletionHandler)
- (void)rmaddy_callBlockWithBOOL: (NSNumber *)b
{
BOOL ok = [b boolValue];
void (^completionHandler)(BOOL result) = (id)self;
completionHandler(ok);
}
#end
- (void)someMethod:(void (^)(BOOL result))completionHandler {
NSThread * origThread = [NSThread currentThread];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL ok = // some result
// do some long running processing here
// Check that there was not a nil handler passed.
if( completionHandler ){
// This assumes ARC. If no ARC, copy and autorelease the Block.
[completionHandler performSelector:#selector(rmaddy_callBlockWithBOOL:)
onThread:origThread
withObject:#(ok) // or [NSNumber numberWithBool:ok]
waitUntilDone:NO];
}
});
});
Although you're not using dispatch_async(), this is still asynchronous with respect to the rest of your program, because it's contained within the original dispatched task block, and waitUntilDone:NO also makes it asynchronous with respect to that.
not sure if this will solve the problem, but how about using NSOperations instead of GCD?:
- (void)someMethod:(void (^)(BOOL result))completionHandler {
NSOperationQueue *current_queue = [NSOperationQueue currentQueue];
// some setup code here
NSOperationQueue *q = [[NSOperationQueue alloc] init];
[q addOperationWithBlock:^{
BOOL ok = YES;// some result
// do some long running processing here
[current_queue addOperationWithBlock:^{
completionHandler(ok);
}];
}];
I wanted to do some tasks on some queue and then execute a completion block as #rmaddy mentioned. I came across the Concurrency Programming Guide from Apple and implemented this (with dispatch_retain & dispatch_released commented out because I am using ARC) -- https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1
void average_async(int *data, size_t len, dispatch_queue_t queue, void (^block)(int))
{
// Retain the queue provided by the user to make
// sure it does not disappear before the completion
// block can be called.
//dispatch_retain(queue); // comment out if use ARC
// Do the work on user-provided queue
dispatch_async(queue, ^{
int avg = average(data, len);
dispatch_async(queue, ^{ block(avg);});
// Release the user-provided queue when done
//dispatch_release(queue); // comment out if use ARC
});
}
Related
I have an IOS project (ARC disabled) which has several view controllers. One particular controller initialises a member object of type MyClass, however when the view controller is dismissed, I'm calling a cleanup method for the object which uses a thread (using dispatch-async) to make some time consuming operations and then when these operations are done im executing a [self release] on the main queue for the object. Is this a good practise, will it cause any errors? Below is a similar example to what im doing:
#implementation ViewController
- (void)viewDidLoad
{
myObj = [[MyClass alloc] init];
}
-(void)viewWillDisappear
{
[myObj cleanup];
}
#end
//myClass
#implementation MyClass
- (void)cleanup()
{
dispatch_queue_t myQueue = dispatch_queue_create ("MyClassDeallocQueue", NULL);
dispatch_async(myQueue, ^{
//time consuming operations
dispatch_async(dispatch_get_main_queue(), ^{
[self release];
});
});
}
#end
Is this a good practise, will it cause any errors?
Currently, your code has an unbalanced retain/release. That is definitely an error (over release).
"Is it good practice?" - well, I don't know what you are trying to accomplish. But if your goal is to keep self alive, until after the block is executed, it is already accomplished purely through the fact that self will be captured. So, strictly a release is not needed.
However, if you NOT explicitly release self on the main thread, you introduce a subtle bug: it might happen that the block has the last reference to self, and since it may execute on some arbitrary thread, it will release self on this non-main thread. And this is forbidden: UIKit methods (including dealloc) MUST be called on the main thread!
Thus, it might make sense:
[self retain];
dispatch_async(myQueue, ^{
// time consuming operation, which captures `self`
[self doSomething];
...
// ensure that `dealloc` will be executed on the main thread, if
// last reference is held by the block:
dispatch_async(dispatch_get_main_queue(), ^{
[self release];
});
});
or shorter:
dispatch_async(myQueue, ^{
// time consuming operation, which captures `self`
[self doSomething];
...
// ensure that `dealloc` will be executed on the main thread, if
// last reference is held by the block:
dispatch_async(dispatch_get_main_queue(), ^{
[self self];
});
});
Edit:
It's an interesting question, whether the "short" version is actually tread-safe or has a race:
Suppose, self will be released in the block executed on myQueue, as the effect of capturing self before it will be retained in the same bock as an effect of capturing self for the block executed on the main queue. Then, we have an issue. Comments appreciated.
I am trying to implement concurrency in objective C. I have a problem with an actions that needs to be run in a synchronized way. The problem here is that I use function that executes a block after completion.
I want to connect to a bluetooth device to run some operations and connect to the next device.
for (Beacon * beacon in beacons) {
[beacon setDelegate:self];
[beacon connectToBeacon];
}
But the connection is asynchronous. The beacon call the delegate (in this case it's the same class) method didConnectSuccess when connection is successful.
I need to wait all my operations in "beaconDidConnect" and deconnection to finish before connecting to the next device.
I currently use a combination of dispatch queue and dispatch semaphore, my semaphore is an ivar
dispatch_queue_t myCustomQueue;
myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL);
for (Beacon * beacon in beacons) {
[beacon setDelegate:self];
dispatch_async(myCustomQueue, ^{
dispatch_semaphore_wait(semaphoreBluetooth, DISPATCH_TIME_FOREVER);
[beacon connectToBeacon];
});
}
In combination with
- (void)beaconDidDisconnect:(Beacon *)beacon
{
dispatch_semaphore_signal(semaphoreBluetooth);
}
Without the dispatch_async, by blocking the callback (beaconDidConnect), the wait was causing a deadlock.
I wanted to dispatch_semaphore_wait in the for loop and not in the dispatch block but the wait causes the callback to wait again, causing a deadlock.
This way it seems to work but I found it a bit ugly.
My other issue is that in my beaconDidConnect method I need to chain asynchronous call and in each waiting the previous to terminate.
All those calls have a termination block, executing when the call is done. I could write instructions in deeper and deeper block but I'd like to avoid this.
I'd need an equivalent of the javascript "promise" concept.
Currently I have something with dispatch queue and dispatch semaphore but I sometimes have deadlock for unknown reason.
Eg :
- (void)beaconConnectionDidSucceeded:(Beacon *)beacon
{
dispatch_semaphore_t semaphoreEditing = dispatch_semaphore_create(1);
dispatch_queue_t editingQueue = dispatch_queue_create("com.example.MyCustomQueue.Editing", NULL);
// First writing procedure
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon writeSomeCaracteristic:caracteristic withValue:value withCompletion:^(void) {
dispatch_semaphore_signal(semaphoreEditing);
}];
});
// A unknow number of writing sequences
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon writeSomeCaracteristic:caracteristic withValue:value withCompletion:^(void) {
dispatch_semaphore_signal(semaphoreEditing);
}];
});
//
// ...
//
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon writeSomeCaracteristic:caracteristic withValue:value withCompletion:^(void) {
dispatch_semaphore_signal(semaphoreEditing);
}];
});
// Terminate the edition
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon disconnectBeacon];
dispatch_semaphore_signal(semaphoreEditing);
});
}
I want to write clear code that execute my instructions in a sequential way.
If your asynchronous methods do have a completion handler, you can "serialize" or "chain" a number of asynchronous calls like shown below:
[self asyncFooWithCompletion:^(id result){
if (result) {
[self asyncBarWithCompletion:^(id result){
if (result) {
[self asyncFoobarWithCompletion:^(id result){
if (result) {
...
}
}];
}
}];
}
}];
Of course, this gets increasingly confusing with the number of chained asynchronous calls, and especially when you want to handle errors, too.
With a third party library which especially helps to overcome these problems (including error handling, cancellation) it may look similar as the code below:
Given:
- (Promise*) asyncFoo;
- (Promise*) asyncBar;
- (Promise*) asyncFoobar;
"Chaining" the three asynchronous methods including error handling:
[self asyncFoo]
.then(^id(id result){
... // do something with result of asyncFoo
return [self asyncBar];
}, nil)
.then(^id (id result){
... // do something with result of asyncBar
return [self asyncFoobar];
}, nil)
.then(^id(id result) {
... // do something with result of asyncFoobar
return nil;
},
^id(NSError*error){
// "catch" any error from any async method above
NSLog(#"Error: %#", error);
return nil;
});
For general info about "Promises", please read wiki article Futures and Promises.
There are number of Objective-C libraries which implement a Promise.
Have you considered use NSOperation and NSOperationQueue?
If you need to wait for every beacon to run a set of operations before continue, you can store every set of operations in a NSOperation and put all the operations inside a NSOperationQueue with a maxConcurrentLimit of 1. It might be easier to cancel/pause/terminate every single operation and the queue will take care of the concurrency.
I kept the dispatch_queue and dispatch_semaphore for the connection but for the writing actions I use a library called Sequencer I found here.
It follows the Promises principle CouchDeveloper talked about.
In my iOS application, I have a database call that takes some time to complete. I have a spinner visible on the screen while this operation is taking place. I am hitting an error with the app crashing with "com.myapp failed to resume in time" so it seems like it is running the database call on the main thread, causing issues.
Current Code
-(void)timeToDoWork
{
...
[CATransaction flush];
[[DatabaseWorker staticInstance] doWork];
//Additional UI stuff here
...
if([self->myReceiver respondsToSelector:self->myMessage])
{
[self->myReceiver performSelector:self->myMessage];
}
}
To get the doWork function to take place on a background thread, it looks like I can use Grand Central Dispatch:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[[DatabaseWorker staticInstance] doWork];
});
However, how do I prevent the execution from continuing until it is complete? Should I end the method after the doWork call, and move everything below it to a new function?
Sample
-(void)timeToDoWork
{
...
[CATransaction flush];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[[DatabaseWorker staticInstance] doWork];
dispatch_async(dispatch_get_main_queue(), ^{
[self doneDoingWork];
});
});
}
-(void)doneDoingWork
{
//Additional UI stuff here
...
if([self->myReceiver respondsToSelector:self->myMessage])
{
[self->myReceiver performSelector:self->myMessage];
}
}
Is there a better way to do this?
Prevent execution in main thread from continuing is really bad idea. iOS will terminate your application since main thread should always work with run loop.
I suggest you following way to handle your problem:
Write a "Locker". Let it show some view with animated spinner and no buttons at all.
When you start dispatch async operation just bring it to the front and let it work with run loop.
When your async operation completes close the locker.
You can also use blocks.
e.g..
- (void)doWorkWithCompletionHandler:(void(^)())handler {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// do your db stuff here...
dispatch_async(dispatch_get_main_queue(), ^{
handler();
});
});
}
And then use it like that:
[[DatabaseWorker staticInstance] doWorkWithCompletionHandler:^{
// update your UI here, after the db operation is completed.
}];
P.S.
It might be a good idea to copy the handler block.
The error you are receiving suggests that you are doing something in application:didFinishLaunchingWithOptions: or applicationDidBecomeAction: or somewhere else in the launch cycle that is taking too long and the app is getting terminated by the launch watchdog timer. Above all, it is vital that you return as quickly as possible from these methods. I'm not sure where your code fits into the launch cycle; but this explanation seems plausible.
There are all sorts of ways to address this; but taking the lengthy process off the main queue is the first step as you noted. Without knowing more about what main queue objects (e.g. UI) depend on this database transaction, I'd say that your suggested solution is perfectly fine. That is, dispatch the work to a background queue; and on completion dispatch the remaining UI work to the main queue.
Delegates were suggested elsewhere as a solution. That's also workable although you still have to concern yourself with which queue the delegate methods get called on.
I think that you should use a delegate in your DatabaseWorker and the method doWork always run in background, so when the worker finish the work it tell to its delegate that the work is finished. The delegate method must be called in the main thread.
In the case that you have many objects that need to know when the DatabaseWorker finish instead to use a delegate I would use notifications.
EDIT:
In the DatabaseWorker class you need to implement the method doWork like this:
- (void) doWork{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//Do the work.
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate finishWork];
});
});
}
And in the class that implement timeTodoWork:
-(void)timeToDoWork
{
...
[CATransaction flush];
[[DatabaseWorker staticInstance] setDelegate:self];
[[DatabaseWorker staticInstance] doWork];
}
#pragma mark DatabaseWorkerDelegate
- (void) finishWork{
//Additional UI stuff here
...
if([self->myReceiver respondsToSelector:self->myMessage])
{
[self->myReceiver performSelector:self->myMessage];
}
}
Also you can use:
[self performSelectorInBackground:#selector(doWorkInBackground) withObject:nil];
instead of:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//Do the work.
});
And add a method:
- (void) doWorkInBackground{
//Do the work
[self.delegate performSelectorOnMainThread:#selector(finishWork) withObject:nil waitUntilDone:NO];
}
My code is like below, I am trying ot call a cpu intensive method inside an async block, but that method is not being always called, sometimes it's called, sometimes not.
-(IBAction) aMethod
//some code
dispatch_async(backgroundQueue, ^{
NSArray *allFiles = [appDel getAllFiles];
totalFilesCount = [allFiles count];
});
//some code
}
backgroundQueue is an instance variable declared in the interface file and created in the viewDidLoad method:
backgroundQueue = dispatch_queue_create("com.myapp.backgroundprocessing", NULL);
The method getAllFiles is sometimes called and sometimes not (checked with breakpoints), the reason I am calling it into a dispatch_async block is that it took a lot of time to return the result. What seems to be wrong with my approach, should it be called in the main thread although it's cpu intensive method?
backgroundQueue = dispatch_queue_create(..., NULL);
creates a serial queue, and not a concurrent queue as you assumed.
Therefore the block dispatched with
dispatch_async(backgroundQueue, ^{ ... });
is executed when all previous blocks dispatched to that queue have finished.
So if the first invocation is still running, it may look as if the second block
is not executed at all.
To create a concurrent queue, you would use
backgroundQueue = dispatch_queue_create(..., DISPATCH_QUEUE_CONCURRENT);
But you should check if it makes sense in your case to start another
(long running) [appDel getAllFiles] operation if the previous operation is still
running.
A possible alternative would be to start another [appDel getAllFiles] operation only
if the previous one has already finished, and to do nothing if the previous operation
is still running. That can be done e.g. with an NSOperationQueue:
if ([opQueue operationCount] == 0) {
[opQueue addOperationWithBlock:^{
NSArray *allFiles = [appDel getAllFiles];
totalFilesCount = [allFiles count];
}];
}
I'm looking for a common and elegant way to manage interfaces update.
I know that user interface code must be run in main thread, so when i need some computation o network task i use GDC with this pattern:
dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue, ^() {
//Backgroud code
dispatch_sync(dispatch_get_main_queue(), ^{
//Update the UI
}
}
The problem with this code is that i need always check if user has changed view during my computation, so the code is like:
dispatch_sync(dispatch_get_main_queue(), ^{
if (mylabel != nil) && ([mylabel superview] != nil) {
mylabel.text = _result_from_computation_;
}
}
There is some best ways?
Thanks.
You pretty well have it. However, in case you want to do more reading or want a more thorough explanation of what's going on...
You should read the Apple Docs Grand Central Dispatch (GCD) Reference and watch the WWDC 2012 video, Session 712 - Asynchronous Design Patters with Blocks, GCD and XPC.
If you're working with iOS, you can disregard XPC (interprocess communication) as it's not supported by the current OS version (6.1 at the time of this writing).
Example: Load a large image in the background and set the image when completed.
#interface MyClass ()
#property (strong) dispatch_block_t task;
#end
#implementation MyClass
- (void)viewDidLoad {
self.task = ^{
// Background Thread, i.e., your task
NSImage *image = [[NSImage alloc] initWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
// Main Thread, setting the loaded image
[view setImage:image];
});
});
}
- (IBAction)cancelTaskButtonClick:(id)sender { // This can be -viewWillDisappear
self.task = nil; // Cancels this enqueued item in default global queue
}
- (IBAction)runTaskButtonClick:(id)sender {
// Main Thread
dispatch_queue_t queue;
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, self.task);
}
In order to cancel and reload the interface later, all you have to do is set the dispatch_block_t variable to nil.
Perhaps more specifically to your problem, this example piece of code deals with Reading Data from a Descriptor, i.e., either the disk or network.
Typically, you would use the Call-Callback pattern which essentially gets a background thread, executes a task, and when completed calls another block to get the main thread to update the UI.
Hope this helps!
You can check the view window property:
if (myLabel.window) {
// update label
}
this is redundant if (label != nil) since if label is nil, then all label properties will also be nil (or zero) and setting them will not raise an exception.