Difference between NSThreads, NSOperations and performSelector - iphone

I want to ask some simple but important questions regarding iPhone development. If we have to perform tasks in the background and when the background tasks are completed we will update the UI, for this we can use NSThreads, NSOperations or (performSelector)performSelectorInBackgroundThread. What is the difference between all these and how they will effect my apps performance.
One more thing, what is the difference between these two statements written bellow:-
[self getData];
[self performSelector:#selector(getData)];
Please explain as i dont know the difference between all these things.

There is actual not a big difference between
[self getData];
AND
[self performSelector:#selector(getData)];
The only difference is when you call [self getData] the compiler can determine that you want to send getData message to the object of class [self class] . And if it can't find any method prototypes, that were declared earlier there would be a warning.
The first and the second lines would be translated to
objc_msgsend(self, _cmd)
performSelector: is really cool thing when you want to do something at runtime (for example you determine at runtime what exact message you want to send to the object). Or here is an example from the "real life": UIButton has method
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
So it stores the action somewhere in it's internals and when there is appropriate control event it calls:
[target performSelector: action];
NSOperation is just a nice way to wrap your work with threads. And NSThread is just wrapper to pthreads.
So your app performance doesn't really depend on the way you're using threads, however it's much easier to do that using NSOperation rather than pthreads.

NSThread is wrapper for pthreads (POSIX threads). pthreads is implemented atop of Mach thread. You can set stack size, priority when you are using NSThread. (By the way, as far as my experience, stack size doesn't affect at all.)
NSOperation/NSOperationQueue is wrapper for Grand Central Dispatch (libdispatch) aka GCD. GCD is implemented atop of pthreads. These are more easily to use than NSThread for many tasks. It reduces boilerplate code for task queueing, thread pool managing and so forth.
performSelectorInBackground: invokes NSThread and treats terminated NSThread. It is the easiest to use in these for only one method invoking.

To make a long story short, you need not work with NSThread yourself most of time, especially if you are working with Objective-C only, and the timing issue is not THAT critical. Implement the behavior using an operation queue or a dispatch queue.
NSOperation is a wrapper or an encapsulation of a certain task. The task could be defined as a method(NSInvocationOperation), or a block(NSBlockOperation), or anything you'd like (by subclassing NSOperation). So the first thing you need to do is to wrap your job in an appropriate way (in a method or a block typically).
Then you will put the operation into an operation queue. Then the operation queue will fire the task in a detached thread as soon as possible.
In iOS 4.0 and later, you can directly feed a block to the queue without building an operation object. Also you can use a different types of job queues, named dispatch queues.
performSelectorinBackgroundThread is similar to the queues as it also creates a thread for you and (effectively) run a method in that thread. It might be handy sometimes, but you still need to be very clear about the unit of tasks that will run on a detached thread. Many Cocoa methods are not thread-safe, and most UIKit operations need to run on the main thread.
That leads to the final concern. You may let detached threads work on the tasks, but updating UI according to their results should run on the main thread. For example, you can do like
[aUIObject performSelectorOnMainThread:#selector(setMessage:) withData:...

Related

Grand Central Dispatch. How Do I Query a Queue to see if it is in use?

What is the best/simplest way to detect if a queue I have created is currently in use? My intent here is to defer a particular action until all queued tasks have completed.
Thanks,
Doug
UPDATE
Here is a bit more context. I have an async serial queue (private dispatch queue) that is a property of my object. When this queue completes its work it calls dispatch_async(dispatch_get_main_queue(), {...}) to up date the UI. Currently the app runs only in landscape interface orientation. I am now adding support for both portrait & landscape interface orientation. For now, I prefer not to allow the interface to rotate to/from portrait/landscape while my GCD async task is running. So in my controller's shouldAutorotateToInterfaceOrientation: method I want to return NO during those periods.
There's no direct support for that in GCD. You can probably get the effect you're looking for in other ways, though.
Do you just want to run a block after other blocks have completed? Put the blocks in a dispatch_group, and submit your "after everything's done action" using dispatch_group_notify. This works with concurrent or sequential queues.
Similarly, put your blocks in a group, and call dispatch_group_wait(group, DISPATCH_TIME_NOW). If it returns non-zero, then there are outstanding blocks in the group.
Is your queue sequential, and you want to wait until the other blocks have completed, blocking the current thread until then? Just issue your handler using dispatch_sync on the same queue.
There are other possibilities, depending on your exact situation.
Edit: Based on your update, there's an even easier way:
add a BOOL property to your view controller, called allowsOrientationChange
override -shouldAutorotateToInterfaceOrientation: to return self.allowsOrientationChange
at the start of your work block, do a dispatch_async to set the property to NO
at the end of your work block, do a dispatch_async to set the property to YES
(There's a little bit of a race condition between when the property is set to NO on the main thread, and when the rest of your work happens in the queue. You could make it a dispatch_sync if that really matters. Depends on what your reasons are for preventing rotation, I suppose.)
If you're in control of all the tasks going into the queue whose completion you care about, you can use the dispatch group APIs to group them together and get notified when they complete. If you aren't using a queue whose tasks you're completely in control of, you can roll your own notification by queueing a block whose sole purpose is to generate such a notification (though this really only applies if you're using a serial queue).

Objective C - Single Background Thread

I want to run a single background thread for an iPhone application which is available in background all the time and gets executed when specific event fires and go to wait for specific event to fire to start its execution again. During the execution of thread if specific event is fired again then thread should restart its work.
I am working on a custom map application. On TouchesMoved event, I need to load the map image tiles according to the positions moved in a background thread. The problem is that when I move the map with speed the touchesMoved event is fired the previous thread has not finished its work and new thread is started. It causes thread safety issue and my application is crashed.
So I am thinking of a solution to have a single thread all the time available and starts its work when touchesMoved is fired if touchesMoved is fired again it should restart its work instead of starting a new thread. I think it will prevent the thread safety issue.
Please help
Firstly I'd echo the use of NSOperation and NSOperationQueue. You could fall-back to using NSThread directly, but the point of NSOperation is that it hides threading from you, leaving you to concentrate on the processing you need to do. Try firing NSOperation requests as and when required, see what the performance is like in your use-case; even if these operations get data in an async manner, it should provide you with a cleaner solution with good performance, plus future proof.
I've successfully used NSInvocationOperation to fire requests as often as required, and it sounds like the sort-of requirements and behaviour you're after. I would suggest more generally that you experiment with these in a test project; here you can test performance.
The following weblog's helped me start playing with NSOperation:
http://www.dribin.org/dave/blog/archives/2009/09/13/snowy_concurrent_operations/
http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/
As always, the Apple Threading Programming Guide is a key read, to figure out which way to go depending on needs.
This sounds like an ideal job for an NSOperationQueue. Have a read of the operation queue section of the concurrency guide.
Essentially, you create an NSOperation object for each map tile load and place them on a queue that only allows them to execute one at a time.
Put a run loop in your background compute thread. Then use an NSOperation queue to manage sending messages to it. The queue plus the run loop will serialize all the work requests for you.

When is a Cocoa callback given controll?

I've been searching around the web for an answer to this one, but was unable to find an answer, on the other side I think it's something quite common thus there is a possibility I'm missing some keywords here. Anyhow, the problem is as follows:
When is control given to a callback function in ObjC (iPhone)?
Does it happen after control is given to a high up in the hierarchy class responsible for the runloop? Can it occur in the middle of another function call being executed?
As an example, let's take the NSURLConnection, we don't know or can't predict when it's going to call didReceiveResponse or the other callback methods, can it be the case that didReceiveResponse get's called when I'm in the middle of another function? (highly doubt that but was unable to find information on callbacks wating for the end of the run loop)
Cheers,
Kaspa
can it be the case that
didReceiveResponse get's called when
I'm in the middle of another function?
No, within a single thread, code is not executed in parallel. The runloop schedules the execution of all messages and dispatches them in sequences. Not even NSTimers are guaranteed to fire to the precision they are theoretically capable of because they have to wait for the runloop like everything else.
The callbacks will not be called from in a middle of your function, indeed. You have to give back control to the main runloop for it to process events, and call your callback.
If you want to know who exactly calls your callback, put a breakpoint in it, and check the stack trace.
The only time the didReceiveReponse will be called while something else is executing, is if you have launched the connection on it's own thread (typically in an NSOperation).
This is why when you do have connections in a background thread, you usually use something like performSelectorInMainThread to change the value for other parts of the application - though you can adjust properties directly if they are not marked nonatomic and are not mutable collections.
By default, basically all cocoa touch classes work entirely in a single thread, including many asynchronous operations like background network calls. The main exceptions are NSOperation and friends, and things related to NSThread.
The OS can do this by inserting its callbacks in the run loop schedule. There are also a few cases when one of your calls will also result in a callback on the same stack - for example, if you call resignFirstResponder on an object that notifies its delegate when this happens, such as UITextField.
A couple relevant blog posts:
quick intro to NSRunLoop
Friendly overview of Objective-C callbacks

Iphone multithreading and AI

I have an ai loop that I would like to write for my iphone app. I am under the understanding that this loop will take along time to make calculations and block the main application.
I want to put it in a different thread and run everything off events.
For example I would have an event that would be called when the players turn started. The AI thread would listen to it and react.
What is the best way for my ai thread to communicate with the main thread? I use NSNotificationcenter a lot but I am reading strange stuff like it will not fire the event on the right thread?
What is the best way to communicate through event like actions with threads?
My recommendation would be to use an NSOperationQueue for your AI processing actions. As the user performs actions, create an NSOperation which handles the AI processing in response of that event and add it to the NSOperationQueue. If there are dependencies between these actions, or if you wish to split your processing up into smaller sub-actions, you can set these actions to process only when certain conditions are met.
Operations placed within an NSOperationQueue will run on a background thread, so they will not block the main thread. For UI updates or other actions that need to be taken on the main thread, I recommend using -performSelectorOnMainThread:withObject:waitUntilDone: to call a method within your operation that posts a notification via NSNotificationCenter's -postNotificationName:object:. Have your view controller or other controller respond to these notifications and do what they need to in response to your AI routine's results.
Instead of firing up a seperate thread manually, I would urge you to consider using NSOperation / NSOperationQueue. It is much easier to work with, far less prone to errors and well documented with tutorials and examples all over the web.
You can use the methods - performSelectorOnMainThread: to execute a given method on the main thread, and - performSelector:onThread: or - performSelectorInBackground: to execute a method on another thread. Using these methods you can fire events across threads.
Note though, to use - performSelector:onThread: a Run Loop must be running on the target thread, else you method will not be executed.
I fire the AI in a background thread with performSelectorInBackground and each time the UI needs to be notified about something (the AI resulting action, a progress bar showing the AI working, etc) I use performSelectorOnMainThread:.
Of course, remember to create a NSAutoReleasePool in the background thread.

NSThread and UIViewController interaction

If I spawn a new thread, and then within it I push a new controller onto my UINavigationController, using code like this...
(a) not working
-(void)myCallbackInThread
{
// move on...
UIApplication* app = [UIApplication sharedApplication];
[app changeView];
}
then I find that the view appears, but does not respond to user input.
If I change the code like this
(b) working
-(void)myCallbackInThread
{
// move on...
UIApplication* app = [UIApplication sharedApplication];
[app performSelectorOnMainThread:#selector(moveToMain) withObject:nil waitUntilDone:FALSE];
}
Then everything works just fine.
Any hints as to why?
In your case, it really depends on what's happening in [app changeView], but the reason it stops responding is most likely that you have no run loop dispatching events on your new, secondary thread (more on this below). In general, however, it is a very bad idea to update the GUI from a secondary thread. As you've already discovered, all of these events should go through the main thread.
The main reason that your second example works and not your first is that UIApplication sets up and handles the run loop and event dispatcher for you on the main thread. So, when you call performSelectorInMainThread, the selector gets dispatched to the main run loop which is able to then handle your gui input and other events. The event dispatcher is also run and managed by UIApplication on the main thread.
So basically, don't perform any GUI management activities on a secondary thread. Dispatch those to the main thread. And if you need processing on a secondary thread (for things like timers or asynch calls, etc.) then you have to start and manage your own run loop on that thread (see NSRunLoop for more on managing your on run loop).
Just found this in the iPhone threading docs
If your application has a graphical
user interface, it is recommended that
you receive user-related events and
initiate interface updates from your
application’s main thread. This
approach helps avoid synchronization
issues associated with handling user
events and drawing window content.
Some frameworks, such as Cocoa,
generally require this behavior, but
it also has the advantage of
simplifying the logic for managing
your user interface.
I still don't see what would actually cause something to display but not be able to receive user input, but I'll follow that guideline in future.
As the documentation says, "If you’re not sure about a particular graphical operation, plan on doing it from your main thread."
A good rule of thumb to follow is that, if a class isn't explicitly documented as being thread-safe, then it's probably not. Additionally, code that's not documented as being thread-safe may not fail fast when used by multiple threads, but may simply exhibit undefined behavior, as you saw.
Almost none of the UI code in UIKit or AppKit is threadsafe. How it fails is irrelevent, because if you are worrying about how it fails you are doing something that is going to result in all sorts of weird bugs that will subtly change between different OS release anyway.
My best advice is to not use things from background threads unless the docs say it is safe.