iOS Mobile App Development: Concurrent Software Application Design

 

Keeping Your Mobile App Responsive

When you create a mobile app, you always want to give the user the best experience possible. You definitely want to avoid situations where your mobile app seems to be hanging or become very slow and unresponsive.

A common situation of an unresponsive mobile app is when you download something that takes a lot of time. Generally, you want the user to continue using your mobile app while something is happening in the background. This is accomplished by using (background) threads, which are processes that handle a task in the background and then notify the mobile app when it's done (but that's not always the case).

Mobile Development and Concurrent Design

Thread programming for mobile apps and software development is not an easy task and comes with many caveats. However, I'll explain it to you in a simple way. So, it is not intimidating.

 

The Main Thread

Every mobile app or software application has at least one thread called the main thread. This is where you do all your operations. You can think of threads like queues that hold events or operations. When an event takes too much time, other events, which have been added to the queue will not be processed until that lengthy event is completed, giving the user the impression that your app is hanging.

In the image below you can see that each block (an event), occupies a certain amount of time. Each incoming block will not be processed until the other blocks have finished.

The solution for this problem is to move all lengthy operations to its separate queue and leave the main queue available for events such as taps or system events. And you do this using threads. But wait! Thread programming is supposed to be hard right? Well, it used to be.

 

GCD and NSOperationQueue

In modern versions of iOS and even OS X, Apple has made thread programming very easy to implement. In the past we relied on an object called NSThread, which, as the name implies, created a thread (also known as a queue) that allowed you to process data or do whatever you needed to do in the background.

But since Objective C and the frameworks have evolved into something more mature, we now have other means of doing thread programming for mobile apps.

GCD (Grand Central Dispatch) and NSOpeationQueue are 2 similar ways of doing things in the background. The difference is that GCD is C based while NSOperationQueue is more Cocoa-like. But both do the same thing.

Let's do something in the background with both GCD and NSOperationQueue:

// using GCD
- (void)doSomethingLengthy {
          dispatch_queue_t myQueue = dispatch_queue_create("some queue", NULL);
          dispatch_async(myQueue, ^{
                    // lengthy operation here
          dispatch_async(dispatch_get_main_queue(), ^{
                   [self updateUI];
                  });
         });
          dispatch_release(myQueue);
}
// using NSOperationQueue
- (void)doSomethingLengthy {
          if (mOperationQueue == nil) {
                   mOperationQueue = [[NSOperationQueue alloc] init];
                   mOperationQueue.name = @"some queue";
          }
         [mOperationQueue addOperationWithBlock:^{
                   // lengthy operation here
                  [[NSOperationQueue mainQueue] addOperationWithBlock: ^{
                              [self updateUI];
                  }];
          }];
}

As you can see, both code examples are similar. However, one uses the C based dispatch queue and the other NSOperationQueue.

NSOperationQueue uses NSOperations to do something. The method addOperationWithBlock allows you to add an NSOperation directly to the queue instead of having to instantiate an NSOperation yourself and manually add it to the queue. (In fact you would use NSBlockOperation if you decide to write it the long way and wrap the individual tasks in a block).

Both examples also have the same peculiarity. Notice, we embed the method [self updateUI] in a block. This block is executed on the main thread (or main queue as it's called here). You should keep that in mind.

Never update your UI in a background thread, bad things will happen and your app may potentially crash.

 

Which is better?

Both GCD and NSOperationQueue are quite good for doing things in the background. However, NSOperationQueue and more specifically NSOperation, offer a way to cancel the task and check if a task has been cancelled. This can be useful when, for example, a user goes into a section of your mobile app that initiates a download, but when the user leaves that section instead of continuing with the download, you can just cancel the operation and prevent battery drainage. 

GCD is a bit simpler and is more appropriate for tasks that may not require cancellation. Since it's C based, the real Cocoa lovers out there may prefer to use NSOperationQueue.

 

Usage? 

As you can see, there's really no reason why you shouldn't do things in the background. However, use this type of design with caution.

When done right and for the correct purposes, it will cause your mobile app to feel very fast and very responsive. If you abuse it, then unpredictable things will happen.

A good start for deciding when to use thread is to know if a particular task will take too much time for the user to notice and feel blocked from continuing action. It's for that same reason that by default network operations, like downloading data, happen in the background on iOS. However, don't overuse it. Don't put everything in a background thread.

Also keep in mind that once the thread has finished, you always do UI operations on the main thread. There are other caveats to consider too.

One of them is for example when you modify an array in that background thread which is also used on the main thread. 

To solve possible crashes or inconsistencies, do the following:

- (void)doSomethingLengthy {
          if (mOperationQueue == nil) {
                    mOperationQueue = [[NSOperationQueue alloc] init];
                    mOperationQueue.name = @"some queue";
          }
         NSMutableArray *imagesCopy = [NSMutableArray arrayWithArray:mImages];
         [mOperationQueue addOperationWithBlock:^{
                    // lengthy operation here
                    // assume anImage is a UIImage generated from some data that was downloaded from a server
                    [imagesCopy addImage:anImage];
                    [[NSOperationQueue mainQueue] addOperationWithBlock: ^{
                              mImages = imagesCopy;
                              [self updateUI];
                    }];
         }];
}
 

 

 

Considering that the variable mImages is an NSArray that is used by the UI, what we first do in this example is make a copy of that variable and use that copy in our lengthy operation. That way if for some reason the UI requires to update the old images, it can still safely do so and the mobile app won't crash.

Once the operation has finished, we replace mImages with the new array and force the UI to update.

That's all there is to it. Feel free to contact me if you have any questions about this subject. Also for more information, I highly recommend you read the following page: click here to read more about concurrent software application & mobile app development using threads.

 


About the Author

Jesus De Meyer has a Bachelor in Multimedia and Communication Technology from the PIH University in Kortrijk, Belgium with 15 years of experience developing software apps for Mac and more than 5 years in iOS mobile app development. He currently works at iTexico as an iOS Developer and in his spare time he works on his own mobile apps.

 

Download our Free E-Book and learn how the Product Mindset can benefit your mobile app. 

Through this guide, we want to give you, product owners, product managers, engineers, entrepreneurs and anybody looking to build great digital products, more insights into the importance of user-centric design and development and how to correctly achieve it.

How Product Mindset Can Save your Sinking App

You may also like:

Post Your Comment Here