views:

2998

answers:

3

What is the difference between NSTimer, NSTask, NSThread and NSRunloop and is there a guideline on when to use each of them?

+13  A: 

Each program runs in at least one thread. You can think of each thread as a separate process of program execution, each running parallel to the others.

If you have some kind of user interface, or other code that needs to listen to events (like network ports), you need a run loop. Every NSThread automatically gets its own run loop, and you very rarely have to concern yourself with them directly. The run loop is also in charge of creating and releasing autorelease pools.

[EDIT: See comments for more discussion about autorelease pools. The most important point to keep in mind is that new threads must take care of setting up an autorelease pool. For example, methods that are invoked with detachNewThreadSelector (see below) should have the following as their first and last lines:

   NSAutoreleasePool *pool = [ [ NSAutoreleasePool alloc ] init ];
   [code here]
   [pool release];

The same applies for threads spawned using other techniques.]

In the main thread, where all the UI handling is taking place, the run loop is very important, since it keeps the interface reactive. That's why you should never run code that's time consuming on the main thread: it will eat up all time on the thread and the run loop will not be allowed to run often enough, resulting in a locked or slow interface. If you need to perform time consuming calculations, or keep a task running in the background, you should create a new thread. Again, you probably don't have to think about the new run loop being created. An easy way of performing a method in a new thread:

[NSThread detachNewThreadSelector:@selector(theSelector) toTarget:self withObject:nil];

Inter-thread communication can be tricky, and you should be aware of the methods performSelector:onThread:withObject:waitUntilDone: and performSelectorOnMainThread:withObject:waitUntilDone: (Great tips on sending NSNotifications across threads here.)

Timers are also handled by run loops. In contrast to run loops, you are likely to often be using timers directly in your program. The very easiest way of creating a timer is:

[self performSelector:@selector(aSelector) withObject:nil afterDelay:1.0];

but sometimes you want to create and manage NSTimer objects yourself, for example to be able to cancel and re-use a timer.

An NSTask is used to run another program as a subprocess of the current one. It's a bit similar to starting a separate thread, but if a subprocess crashes, your main program will keep running. Communication between programs is also very different from communication between several threads in the same process.

You tagged your question with "iphone", and on the iPhone you will never be using NSTasks.

NSOperations are used when you need to handle a larger amount of different tasks, placing them in queues and/or processing them in separate threads (although they don't have to run in separate threads). If your application needs to create just a few, specialized threads, then there is no reason to use the NSOperation class. But if you will routinely generate tasks (like communicating with a server) that must be kept track of, NSOperation and NSOperationQueue will come in handy.

Felixyz
“The run loop is also in charge of creating and releasing autorelease pools.” Close. NSApplication does this (on the main thread), not NSRunLoop. If you spawn your own thread, you have to create your own pool. (I cite the NSAutoreleasePool docs: “NSAutoreleasePool objects are automatically created and destroyed in the main thread of applications based on the Application Kit …”.)
Peter Hosey
I think you are both wrong. If you look at the boilerplate main.m file, *this* is where the NSAutoreleasePool is created and managed. There is NO correlation between a runloop and an autoreleasepool near as i can tell.
Lounges
The run loop has an autorelease pool that it drains through every cycle. NSApplication could not be responsible because it has no way to drain it and it does not call your code. There's usually also one autorelease pool in main, but apart from initialization time it is not ever used.
Nikolai Ruhe
The Cocoa application project template does not create an autorelease pool in `main`; it simply tail-calls `NSApplicationMain`. NSApplication does create an autorelease pool—this is *explicitly documented* in the documentation of both NSApplication and NSAutoreleasePool. Moreover, the Threading Programming Guide explicitly says that if you create a thread, you must create an autorelease pool (http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_5.html#//apple_ref/doc/uid/10000057i-CH15-SW14 ).
Peter Hosey
+3  A: 
  • NSTimer is a timer object, a way to invoke a selector on an object in the future.
  • NSThread is a thread class. I suppose you know what a thread is.
  • NSTask is a process class, a way to run another program from your program.
  • NSOperation (I'm adding to the question) is a very nice abstraction for a single task. You embed your operation in this class and you can easily execute concurrently by means of an NSOperationQueue class.
  • NSRunLoop is the most difficult to understand. In some way abstracts and adapts the select() unix system call, managing input sources and dispatching events and timers on a thread.

The guideline is the Apple Threading Programming Guide.

IlDan
+1  A: 

The other answers do a pretty good job of summing up timers, tasks, and threads. I wanted to comment a bit more about the NSRunloop as I think most of the other answers still leave some confusion here. From the NSRunloop documentation:

An NSRunLoop object processes input for sources such as mouse and keyboard events from the window system, NSPort objects, and NSConnection objects. An NSRunLoop object also processes NSTimer events.

also

In general, your application does not need to either create or explicitly manage NSRunLoop objects. Each NSThread object, including the application’s main thread, has an NSRunLoop object automatically created for it as needed. If you need to access the current thread’s run loop, you do so with the class method currentRunLoop.

Think of the NSRunloop as the main event processing and dispatching loop for a particular thread. It reads from the input devices, services any objects that need to be serviced, and dispatches the data appropriately.

Lounges
Basically all user input processing takes place in the main thread, although other threads might of course listen to other kinds of events. However, in many threads, the runloop plays no discernible role for the developer, like when you just want to run a time-consuming calculation in the background.
Felixyz