I have some data calculation method (let it be "myMethod:"), and I want to move the call to another thread because I don't want to block my main UI functionality. So, started to do some research on how to call my method on another thread. As far as I see, currently, there are a lot of different ways for doing that. Here's a list:
a) using pure threads (available since iOS 2.0):
[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];
b) using a simple shortcut (available since iOS 2.0). Available from inherited NSObject but the method belongs to NSThread class too:
[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];
c) using a new approach of Grand Central Dispatch queues (available since iOS 4.0):
dispatch_async(dispatch_get_global_queue(0, 0),
^ {
[self myMethod:_myParamsArray];
});
d) somehow, using some classes such as NSOperation, NSBlockOperation or NSOperationQueue, though not sure how exactly to do it (some example would be appreciated)
Currently, I have used case "b" but curious about pros and cons and other related suggestions on that.
UPDATE: e) also found another way for performing similar threading stuff - Run loops. Here's an excerpt from apple docs:
A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.
IMHO, more or less your are dealing with the same task - how to call your method on separate thread for its async operation.
UPDATE2: Already had some experience with NSInvocationOperation and NSOperationQueue and IMHO it's quite convenient. According to Apple docs, GCD and NSOperations are a preferred way for implementing multithreading. And also, NSOperations runs on GCD starting from iOS 4.0. In short, you instantiate NSIvocationOperation (as a call to your method) then instantiate NSOperationQueue and add invocation to the queue. NSOperationQueue is smart thing enough, you can instantiate multiple NSIvocationOperation objects (wrapping your method calls) and them to NSOperationQueue. The rest is assured. NSOperationQueue determines how much parallel threads it need to perform the calls (NSInvocationOperation) and handles it for you. It might execute first call on thread A, then second on thread B, third on thread C and forth on thread B, so you do not have to worry about that. But if you want, you may tell how max threads NSOperationQueue can use for performing calls (for example 1) but I have no need for that. By default, all tasks are performed on other than main thread, so operation queues are asynchronous by default. Also, if you want to perform your method calls (each wrapped in separate NSInvocationOperation) in a strict queue then you can add dependencies and so NSOperationQueue will preserve method call order. Here's an example:
// wrap your method call into NSInvocationOperation object
NSInvocationOperation *currentOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(yourMethodCall) object:nil];
// _sharedOperationQueue is a shared NSOperationQueue
// get all executing operations from the queue and get the last operation
_lastOperation = [[_sharedOperationQueue operations] lastObject];
// check if _lastOperation is not nil
if (_lastOperation) {
// if not then add dependency, so the calls would be performed in a queue
[currentOperation addDependency:_lastOperation];
}
// say - execute my method (operation)
[_sharedOperationQueue addOperation:currentOperation];
_lastOperation = currentOperation; // mark as last operation for adding dependency to the next operation
// the queue will retain invocation operation so you will release
[currentOperation release];
..... you can create another NSInvocationOperation and add it to the queue....
As for RUNLOOPs, still, sometimes you will face them, for example when starting/scheduling a timer, or making NSURL connections. IMHO, a runloop might be compared to a queue of tasks executed on one thread. IMHO a runloop is a pointer to a thread that operates as a queue: it has tasks that might throw events and they will be placed at the end of the queue in that thread. By default all tasks in your app run in a single runloop - in a single thread. I'm saying it's a pointer because when your app generates events then the app must know where to put that event (touch event or other delegate callback) for execution. Of course, you should read about runloops for more detailed information because these are just my thoughts.