How Important is it to use `performSelectorOnMainThread:withObject:waitUntilDone:` From an NSOperation?
My iPad app syncs with an XML feed, running the sync in an NSOperation subclass executed from an NSOperationQueue. As it parses the feed, it calls back to the main thread via performSelectorOnMainThread:withObject:waitUntilDone:
to update various parts of the UI, schedule downloads, etc. Some of this is pretty expensive; the UI can sometimes become unresponsive for a second or two as a sync is going on.
To make the UI more responsive, I've removed the use of performSelectorOnMainThread:withObject:waitUntilDone:
in favor of direct calls to perform all the sync-related tasks, including updating the UI. So now the sync takes place entirely on the background thread created by the NSOperationQueue. This seems to work pretty well, and the UI is much more responsive during a sync.
However, I'm leery of releasing with it this way. I've seen some mentions in various places that one should only update the UI on the main thread (example with reference to App开发者_如何学运维Kit). But I've been unable to find anything specific on this topic in the documentation.
So how important is it to update the UI on the main thread? Which parts of an app are thread-safe and which are not? Is there perhaps a reference explaining what's safe to execute in an NSOperation and what should be executed only on the main thread in iOS? Am I really doing something unsafe or crash-prone?
It is extremely important that you always update the UI on the main thread. Touching the UI from a background thread can cause all sorts of issues, including corruption of internal state, crashes, or just plain incorrect behavior. Any work that doesn't require touching the UI should go ahead and do on the background thread, but the bits of code that update the UI definitely needs to happen on the main thread.
The Thread Safety Summary in the Threading Programming Guide discusses which Foundation classes are thread-safe and which aren't. The whole summary is worth a skim for quick answers to common questions.
The Thread Programming Guide also has a very brief section on Threads and Your User Interface, where “it is recommended that you receive user-related events and initiate interface updates from your application’s main thread,” and “Some frameworks, such as Cocoa, generally require this behavior.” No cross-reference to a discussion of this Cocoa requirement, but I imagine I'll run across it eventually.
But the upshot is that, according to this document it is important to perform UI updates on the main thread.
Are you sure you need the NSOperation? NSXMLParser.parse and NSURLConnection.start are already asynchronous. If the class that you're parsing updates some model object, and your view controller observes that model object using KVO, you might wind up with simpler, better performing code.
There is further documentation and discussion in a technical note that goes with the ListAdder sample code. It's TN2109: 'simple and reliable threading with NSOperation'. It repeatedly talks about only updating UIKit elements from the main thread and gives examples of correct and incorrect implementations. You might find further references to it by searching 'thread confinement'.
精彩评论