Currently I'm using NSThread to cache images in another thread.
[NSThread detachNewThreadSelector:#selector(cacheImage:) toTarget:self withObject:image];
Alternately:
[self performSelectorInBackground:#selector(cacheImage:) withObject:image];
Alternately, I can use an NSOperationQueue
NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(cacheImage:) object:image];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:invOperation];
Is there any reason to switch away from NSThread? GCD is a 4th option when it's released for the iPhone, but unless there's a significant performance gain, I'd rather stick with methods that work in most platforms.
Based on #Jon-Eric's advice, I went with an NSOperationQueue/NSOperation subclass solution. It works very well. The NSOperation class is flexible enough that you can use it with invocations, blocks or custom subclasses, depending on your needs. No matter how you create your NSOperation you can just throw it into an operation queue when you are ready to run it. The operations are designed to work as either objects you put into a queue or you can run them as standalone asynchronous methods, if you want. Since you can easily run your custom operation methods synchronously, testing is trivially easy.
I've used this same technique in a handful of projects since I asked this question and I couldn't be happier with the way it keeps my code and my tests clean, organized and happily asynchronous.
A++++++++++
Would subclass again
In general you'll get better mileage with NSOperationQueue.
Three specific reasons:
You may want to initiate caching of many items at once. NSOperationQueue is smart enough to only create about as many threads as there are cores, queuing the remaining operations. With NSThread, creating 100 threads to cache 100 images is probably overkill and somewhat inefficient.
You may want to cancel the cacheImage operation. Implementing cancellation is easier with NSOperationQueue; most the work is already done for you.
NSOperationQueue is free to switch to a smarter implementation (like Grand Central Dispatch) now or in the future. NSThread is more likely to always be just an operating system thread.
Bonus:
NSOperationQueue has some other nice constructs built-in, such as a sophisticated way of honoring operation priorities and dependencies.
I would use NSOperationQueue. Under OS 3.2, NSOperationQueue uses threads under the hood, so the two methods should perform similarly. However, under Mac OS 10.6, NSOperationQueue uses GCD under the hood and so has the advantage of not having the overhead of separate threads. I haven't looked at the docs for OS 4, but I'd suspect it does something similar--in any case, NSOperationQueue could swap implementations if/when the performance advantages of GCD become available for the iPhone.
Related
When you use threads, do you have any preferences? In general rule, to use any of these techniques :
create a new thread manually and use the run loop
use NSOperationQueue
or use Grand Central Dispatch and the C version with dispatch_queue?
Does NSOperationQueue simplify everything, and thus is better to be used when we need to create an asynchronous function?
I'm lazy, so my philosophy is to pick the simplest solution that does everything I need it to. (I like to think this is the "lazy" espoused by Larry Wall but sometimes I wonder.)
So my order of preference would be:
Asynchronous method calls
NSOperationQueue
Grand Central Dispatch
Thread
There an increase in complexity and flexibility with each step down. If you need the extra flexibility then the complexity is probably worth it.
I can remember that in a WWDC 2010 session it was said that GCD is the way to go unless you are working with APIs that currently do not work well with it.
As a general rule, I always use asynchronous method calls for networking and avoid using pthreads or NSThreads directly unless it is absolutely necessary.
Is there a way implement multi threading in IPhone using xcode? Could you refer me to few tuts that I could use.
Thanks and Regards
Abishek R Srikaanth
The easiest way to implement multi-threading is probably going to be using NSOperationQueue. You subclass NSOperation, or create an NSBlockOperation with the code block you want to run in the background. Set a completion block if you need to be notified on the main thread when the background task finishes. Then add your operation to an NSOperationQueue and you're set! You can also set dependancies on the operation to run a series of events one at a time, or add many operations to the queue if you don't care what order they're executed in.
There are other ways of doing threading, but NSOperation is especially nice since it wraps everything up into a neat unit of work, where you're less likely to make shared memory mistakes, and also you can trust NSOperationQueue to look at the number of cores in your device and do the right thing when it comes to running many operations at once.
I have some simple doubts about NSOperation and GCD that I have not found answer to on the documentation.
The firs question is related to memory management:
I want to know if I need to create an Autorealease pool for the methods I wil add to the NSOperationQueue; similarly to when you run a method on different thread without NSOperations.
The next question is whether NSOperation takes care of GCD or if this needs to be done manually?
Thank you for your help!
I just saw your question here and there is a post on the apple dev forums you might be interested in. According to one of the apple guys on this thread so long as you run your NSOperation through an NSOperationQueue you do not need to create your own autorelease pool as the NSOperationQueue does it for you.
Also the docs for NSOperationQueue apparently need to be updated/corrected. On devices running iOS 4 or later NSOperationQueue does use GCD despite what the class reference documents say.
According to the documentation, you should create an NSAutoreleasePool in the main method of your NSOperation. The documentation for NSInvocationOperation and NSBlockOperation doesn't specify whether they create an autorelease pool for you, so to be safe it would be best to create one when using those classes too.
The NSOperationQueue handles queuing and executing the operations, so you shouldn't have to mess with GCD yourself for tasks related to the operation queue.
I'd like to know what is the proper way to dealloc an ivar NSOperationQueue in case it has still some operations running, which can typically occur when the user suddenly quits the app. In some examples I saw the waitUntilAllOperationsAreFinished was used, like this:
- (void)dealloc {
[_queue cancelAllOperations];
[_queue waitUntilAllOperationsAreFinished];
[_queue release];
...
however many suggest to avoid doing so since it would hang the run loop. So what is the proper way to release the _queue? And what happens if I don't wait for operations to be finished and just go on with the release?
In almost all cases, calling cancelAllOperations will be sufficient. The only time you need to call waitUntilAllOperationsAreFinished is if you actually need to ensure that those operations are done before you move on.
For example, you might do so if the operations are accessing some shared memory, and if you don't wait then you'll end up with two threads writing to that shared memory at the same time. However, I can't think of any reasonable design that would protect shared memory by causing a blocking delay in a dealloc method. There are far better sychronization mechanisms available.
So the short answer is this: you don't need to wait for all operations to finish unless there's some reason your application specifically needs it.
I'm confused about the concept of "threads" in iPhone development:
Why are threads necessary / useful?
How can threads be used in Objective-C?
You need multi-threading in objective c because sometimes you need functions/code to run "in the background" (read: on another thread). For instance (but not explicitly) you might need to download large amounts of data off the internet (a picture, or a video).
In this case running the download on the 'main' thread will cause the iphone to freeze before the download is complete. So you use multi-threading to download the data AND let the iphone work all at the same time.
There are lots of ways to do multithreading in objective-c. To be honest you need to look it up yourself, we're not here to just spoonfeed you.
Things to look up are: NSURLConnection and the method [self performSelector:onThread:...]
More simple...If you want to run some methods(processes) parallely you can use threads...One thread is doing one stuff while another doing other stuff... So u can use threads if you need something to be done when another thing is doing...
Example: Thread 1: sending request to server
Thread 2: preparing information(image,text etc) to be sent.
So in general this is the purpose of threads
Recently, Apple suggests that programmers should move away from thread and use an alternative solution with more advantages, better performances and much more easier to implement; it's Concurrency Programming:
http://developer.apple.com/library/mac/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091
The recommended way to implement concurrency is using queues.
For those who just want to execute a method / block in a separate thread - use this code:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[self longMehtod];
});
for further information read the Concurrency Programming Guide from Apple