A bit of prehistory: I first wrote Keep Calm on Android about a year ago and the whole app run on the UI thread. All posters were generated, saved, edited, etc on one thread (unless the system did it on another thread for me, which it generally didn’t). I then learnt the quirks of concurrency on Android and I thought great, now the app should run a little smoother. By last summer when I was writing the first version of Keep Calm on iOS I had fallen in love with concurrency, and even the version currently in the store uses about thirty odd threads (hence why it is so slow, and I’m pushing an update).
Firstly, concurrency is absolutely vital in making a good app. You can’t do network communications, heavy file IO or complex processing on the UI thread because it will begin to become unresposive.
Secondly, don’t use performSelectorInBackground: when you need to do something more than once in the background. It creates a whole new thread which is often completely unnecessary. The superior alternative is to use NSOperationQueue. My current pattern is to use a single background queue across the application because creating additional queues is unnecessary: one NSOperationQueue doesn’t represent a single thread (unless you limit it to) and can run several operations concurrently, so there is no real need to create new queues.
Thirdly, it is far too easy to over-use concurrency. I found myself doing loads of UI operations on another thread which eventually meant I was drawing things about three times and just wasting time and processing power.
I have a new rule for working with concurrency: the view and controller layers (I use MVC, as one should with iOS development) should operate on a single main thread however the controller can instantiate tasks on the Model layer either on the main thread or on my separate NSOperationQueue. My reasons for this are because it reduces complexity, is easy to understand and actually ensures that the app ends up being pretty quick. Obviously there are some tasks that the controller may ‘do’ in a separate thread, however I consider them to be Model tasks.