Run method within a method without completion - iphone

So I have two methods
-(void)someMethod
{
[self someOtherMethod];
//Do some other stuff
}
-(void)someOtherMethod
{
//Do some other stuff
}
And I was wondering if it is possible to run someOtherMethod as shown in the code above, but without waiting for someOtherMethod to finish running before continuing on.

dispatch_async(... some queue ..., ^{
[self someOtherMethod];
});
Note that you can use one of the global concurrent queues, but you need to be careful to not pound on it or you'll end up with dozens of threads. You may want to create your own concurrent serial queue and enqueue there.

Related

self performSelector:withObject: afterDelay: does not call method

I am developing an iPhone application where I'm trying to call particular method after certain delay. But the method is not getting called. I have no clue why its not getting called.
Here is my code
-(void)gettingCommentsList { // some stuff....
[self performSelector:#selector(callGetListInBackgroundMethod) withObject:nil afterDelay:1.0]; }
-(void)callGetListInBackgroundMethod {
isFromthread =YES;
NSLog(#"callGetListInBackground");
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Add code here to do background processing
//
//
[self gettingCommentsList];
dispatch_async( dispatch_get_main_queue(), ^{
// Add code here to update the UI/send notifications based on the
// results of the background processing
[self.commentsTbl reloadData];
});
});
}
Thanks
One potential problem is that timers do not prevent threads from exiting before the timer's fired. So if the run loop (of the thread which calls -performSelector:withObject:afterDelay:) has no other source (work), it may not continue running for one second or more and the thread will exit before your timer fires (and your custom work is executed).
That's certainly possible if you schedule the timer on a secondary thread.
I suspect the reason for this design is because timers may be configured as recurring (or not) -- a lot of people would end up with 'zombie' threads because those recurring timers would never be invalidated. That problem could easily chew up a ton of system resources.
Make sure you are not calling [NSObject cancelPreviousPerformRequestsWithTarget:self]
You seem to be calling each method from the other -
In gettingCommentList, you call
[self performSelector:#selector(callGetListInBackgroundMethod) withObject:nil afterDelay:1.0];
and in callGetListInBackgroundMethod in dispatch_async you call
[self gettingCommentList];
Edit:
Try making the call just once and see if it works. If it does, it might be that you're not done with the first call before the second one begins, hence the problem. Let me know what happens.
Edit 2:
I tried your code. The problem is the the subsequent calls to gettingCommentList are in the background thread rather than the main thread. So I did this:
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Add code here to do background processing
//
dispatch_async( dispatch_get_main_queue(), ^{
[self gettingCommentsList];
});
});
and it works. But make sure you don't call the two functions continuously as this would make them run all the time, which I'm sure you don't really want :-)

Perform selector with a callback = concurrency?

I'm having a tiny question on a situation I'm facing.
I have 2 methods :
- (void)firstSelector {
[self launchAsyncTask];
... do some work for a long time (10secs) ...
}
- (void)asyncTaskFinished {
... some work after 5secs of async task ...
}
firstSelector performs launchAsyncTask which is just a background task that has a callback called asyncTaskFinished.
Assuming that firstSelector runs for a certain time after launching the async task (let's say 10 seconds), and that the async task runs for 5 seconds, will there be a concurrency problem?
How does this work under the hood?
Will asyncTaskFinished be executed after firstSelector, or firstSelector will be paused to run asyncTaskFinished?
Is there a link with run loops? Are methods added to a queue and then executed as I call them?
I'm lost :)
Thank you.
Async tasks run asynchronously which do not run on the main run loop while UI runs on the main loop. Have a look at the Concurrency Programming Guide.
So here in your case, you are not really sure about how long the sync time is going to take. You are assuming that it might take 10 sec but it is not completely sure. So, in this case you will need to work with block or find a way to trigger the asyncTaskFinished function when the async task completed on the main thread. You could define a simple block callbacks and then trigger the function when the async task finishes.
If you use GCD for async task, it becomes really easy. You would do just this much;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self runMyAsyncTask];
// trigger the main completion handler when this completed
dispatch_async(dispatch_get_main_queue(), ^{
[self asyncTaskFinished];
});
});
If you use NSThread for concurrency you could use performSelector:onThread: to trigger the completion selector when the async task finishes. For a simple case, I will show you to implement a callback handler. You could create a function like this to trigger the async task,
-(void)launchAsyncTaskWithCompletionHandler:(void(^)(void))completionHandler{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self runMyAsyncTask];
// trigger the main completion handler when this completed
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler();
});
});
}
And calling this is relatively simple;
[self launchAsyncTaskWithCompletionHandler:^{
[self asyncTaskFinished];
}];
This is easy to understand and makes your code much clearer. Hope this helps you.
A thread's run loop executes tasks from its input sources in a sequential (non-concurrent) fashion. Therefore, you do not need to worry as long as firstSelector and asyncTaskFinished are executed in the same run loop. This will depend on the callback semantics. You may need to use something like performSelector:onThread:withObject:waitUntilDone: to ensure the asynchronous callback function is executed in the correct thread.

How do I kill/suspend/close an asyncronous block in GCD?

I've implemented a block that is dispatched asynchronously using GCD as follows:
__block BOOL retValue;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
retValue = [self GCDHandler:actionName WithServiceType:serviceType :arguments];
});
return retValue;
How do I cancel such a block if it is running for longer than I would like? Is there a way to cancel GCD-dispatched blocks, or provide a timeout to them?
There is no built in way to cancel GCD blocks. They're rather set and forget. One way I've done this in the past is to provide 'tokens' for blocks.
- (NSString*)dispatchCancelable:(dispatch_block_t)block
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
if (!checkIfCanceled)
block();
}
return blah; //Create a UUID or something
}
- (void)cancelBlock:(NSString*)token
{
//Flag something to mark as canceled
}
That depends on what your GCDHandler is doing. There's some pretty good videos about GCD on the Apple dev site - you might want to move up a layer (into Cocoa) and use NSOperationQueue and NSOperations (either your own subclass or NSBlockOperation). They're all built on top of GCD and the abstraction layer might be more appropriate for what you are trying to do (which you don't state - is it a network request? etc.)

Dispatch Queues with Multiple Methods ? iPhone

I am trying to learn more about dispatch queues. If I put three methods in a dispatch queue as in the code below, do they execute one after the other or all at once ?
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^ {
[activeModel release];
[mainViewController showSceneList];
[mainViewController removeTidyUpScreen];
});
How would I specify that the next should not run until the previous one is completed ?
Think of a block -- the code you submit to a dispatch queue as you have here -- as an anonymous function. So, the code you have in your block here executes in order just as if you were calling a function that contained the same calls, one method, then the next, and so on.
In your particular example, it looks like you may be doing some operations with the UI on a queue that is not the main queue. You MUST do UI operations on the main queue, because it has access to the UI. You might use dispatch_get_main_queue() instead, to be sure you're getting that queue. If you have something you want to run in the background that will not touch the UI, then using a global queue is fine, and preferred especially if not stalling the UI is important.

Grand Central Dispatch (GCD) vs. performSelector - need a better explanation

I've used both GCD and performSelectorOnMainThread:waitUntilDone in my apps, and tend to think of them as interchangeable--that is, performSelectorOnMainThread:waitUntilDone is an Obj-C wrapper to the GCD C syntax. I've been thinking of these two commands as equivalent:
dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; });
[self performSelectorOnMainThread:#selector(doit:) withObject:YES waitUntilDone:YES];
Am I incorrect? That is, is there a difference of the performSelector* commands versus the GCD ones? I've read a lot of documentation on them, but have yet to see a definitive answer.
As Jacob points out, while they may appear the same, they are different things. In fact, there's a significant difference in the way that they handle sending actions to the main thread if you're already running on the main thread.
I ran into this recently, where I had a common method that sometimes was run from something on the main thread, sometimes not. In order to protect certain UI updates, I had been using -performSelectorOnMainThread: for them with no problems.
When I switched over to using dispatch_sync on the main queue, the application would deadlock whenever this method was run on the main queue. Reading the documentation on dispatch_sync, we see:
Calling this function and targeting
the current queue results in deadlock.
where for -performSelectorOnMainThread: we see
wait
A Boolean that specifies whether the
current thread blocks until after the
specified selector is performed on the
receiver on the main thread. Specify
YES to block this thread; otherwise,
specify NO to have this method return
immediately.
If the current thread is also the main
thread, and you specify YES for this
parameter, the message is delivered
and processed immediately.
I still prefer the elegance of GCD, the better compile-time checking it provides, and its greater flexibility regarding arguments, etc., so I made this little helper function to prevent deadlocks:
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
Update: In response to Dave Dribin pointing out the caveats section ondispatch_get_current_queue(), I've changed to using [NSThread isMainThread] in the above code.
I then use
runOnMainQueueWithoutDeadlocking(^{
//Do stuff
});
to perform the actions I need to secure on the main thread, without worrying about what thread the original method was executed on.
performSelectorOnMainThread: does not use GCD to send messages to objects on the main thread.
Here's how the documentation says the method is implemented:
- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait {
[[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes];
}
And on performSelector:target:withObject:order:modes:, the documentation states:
This method sets up a timer to perform the aSelector message on the current thread’s run loop at the start of the next run loop iteration. The timer is configured to run in the modes specified by the modes parameter. When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in one of the specified modes; otherwise, the timer waits until the run loop is in one of those modes.
GCD's way is suppose to be more efficient and easier to handle and is only available in iOS4 onwards whereas performSelector is supported in the older and newer iOS.