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 task (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 data that is divided up to mulitple workers then merged to produce the result to hand to the consumer. I will talk about that in a future article.
For concurrent i/o, I designed a simple app called 4Loader that utilizes an overall Model-View-Controller application architecture, and for concurrency is guided by a “request-control-operation-task-event” pattern (i use these terms loosely to not refer to other well-known design patterns by similar names). In its current form, the app has four hard-coded URL of San Francisco images that are downloaded when the user taps one of the quadrants in the view and touches Go. The image in quadrant 1 is over 3MB in length, and the other three are various sizes. The point is to demonstrate how the app handles i/o concurrency by starting the download of the image in the first quadrant, then seconds later, the user downloads another image or two in 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 the download is completed, results in an error or times out. NSURLConnection, in its asynchronous form, it utilized to capture the data and keep progress updates. Download images are cached with a custom NSCache object (only for demo purposes. I would use a different storage/caching scheme for large image downloads). At the operations layer, Grand Central Dispatch is used to handle callbacks to main queue (through Delegation) to update UI (progress updates, displaying the image or timeout alerts).
The code is available at github.