As I have been digging deeper into multi-threading aspects of iOS development, I wanted to investigate several “patterns” for application architecture to support concurrent i/o (downloading/networking), and multi-processor/multi-core CPU bound tasks (batch calculations and processing of large data sets).
For CPU bound tasks, I like to refer to a generic producer-worker-consumer pipeline pattern where the producer supplies a data stream that is divided up and passed to multiple workers. The output from the workers are merged to produce a result to hand off to the consumer.
To demonstrate the concurrent i/o concept, I designed a simple app called 4Loader that utilizes an overall Model-View-Controller application architecture. For concurrency, it is guided by a “request-control-operation-task-event” pattern (i use these terms loosely so as not to refer to other well-known design patterns by similar names). In its current form, the app has four hard-coded URLs of San Francisco images that are downloaded when the user taps one of the quadrants in the view and taps Go. The image in quadrant 1 is over 3MB in size, and the other three are various smaller sizes. The point of the app is to demonstrate how it handles i/o concurrency by starting the download of the larger image in the first quadrant. Then, seconds later, the user downloads another image or two from the other quadrants. Concurrency is “happening” at the networking layer (task-event) while the concurrent operation (the client to the networking task) maintains state in the form of the quadrant view that requested the download.
Check out the demo. On the controller layer, It utilizes NSOperationQueue to manage the concurrent DownloadOperations (which are NSOperation subclasses). Each DownloadOperation also fires off a NSTimer for timeouts which execute in its own NSRunLoop. In additional, to maintain the networking layer, the operation layer keeps an NSRunLoop “alive” until either the download is completed, results in an error or times-out. NSURLConnection, in its asynchronous form, is utilized to capture the data and maintain progress updates. Downloaded images are cached with a custom NSCache object (Note that this is only for demo purposes. In a production app, I prefer to use a different storage/caching scheme for large image downloads). At the operations layer, Grand Central Dispatch is deployed to handle callbacks to the main queue (through Delegation) which updates the UI (progress updates, displaying the image or timeout alerts).
The code is available at github.