Even though the iPhone 5 and the iPad 4 ship with a powerful A6(X) processor and a lot more RAM than the original iPhone, this doesn't mean that iOS applications are by definition fast and performant. In this quick tip, I will give you five tips to improve application performance.
1. Caching
If an iOS application fetches a remote resource, it is important that it doesn't fetch that same resources every time it needs to access it. If you plan to develop a Twitter client for iOS, for example, then the client shouldn't be downloading the same avatar every time it needs to display it. Caching the avatar will significantly improve application performance.
What is caching? The basic idea of caching is simple. When the application fetches a remote resource for the first time, it stores a copy of that resource on disk for later use. If that same resource is needed later, the application can load it from disk instead of fetching it remotely. The added benefit is that the resource is also available when the device is not connected to the web. The complex aspect of caching is how to store the resource, when to store it, and, most importantly, when to refresh it.
Olivier Poitrey has developed a small library named SDWebImage that is aimed at caching images. It provides a category on UIImageView
much like AFNetworking does. The key difference is that SDWebImage caches the images it downloads. Images are downloaded in the background and each images is decompressed, resulting in faster load times. The library leverages Grand Central Dispatch to keep the main thread responsive. If your application works with remote images, then you should take a look at this gem.
2. Do Not Block the Main Thread
One of the most important lessons to learn when developing for the iOS platform is to never block the main thread. If you block the main thread with a long running operation, such as downloading images or other resources, your application will become unresponsive as long as the operation isn't completed. Make it a habit to move long running tasks to a background thread. Even if you only need a handful of bytes, if the device's connection to the web is slow, the operation will still block the main thread.
Writing safe multithreaded code has become a lot easier with the introduction of Grand Central Dispatch. Take a look at the following code snippets. The first snippet downloads data on the main thread, while the second snippet leverages Grand Central Dispatch to perform the same task on a background queue.
NSData *data = [NSData dataWithContentsOfURL:URL]; UIImage *image = [UIImage imageWithData:data]; [imageView setImage:image];
dispatch_queue_t queue = dispatch_queue_create("downloadAsset",NULL); dispatch_async(queue, ^{ NSData *data = [NSData dataWithContentsOfURL:URL]; dispatch_async(dispatch_get_main_queue(), ^{ UIImage *image = [UIImage imageWithData:data]; [imageView setImage:image]; }); });
3. Lazy Loading
Being lazy isn't always bad especially if you are a programmer. Lazy loading is a well known concept in software development. It simply means that you postpone the instantiation of an object until you need the object. This is advantageous for several reasons. Depending on the object and the cost for instantiation, it can dramatically improve application performance and memory usage. Lazy loading objects isn't a difficult concept. The simplest implementation of this pattern is overriding the getter of a property as shown below.
- (MyClass *)myObject { if (!_myObject) { _myObject = [[MyClass alloc] init]; } return _myObject; }
The lazy loading pattern can be applied in many areas of software development. For example, if part of your application's user interface is not shown by default, it may be advantageous to postpone its instantiation until that part is about to be shown.
Table and collection views use a combination of caching and lazy loading to optimize performance. If the next cell or item is about to be displayed on screen, the table or collection view looks for a cell or item it can reuse (caching). Only if no reusable cell or item is available will the table or collection view (or its data source) instantiate a new cell or item (lazy loading).
4. Measure Performance
If you notice that your application is slow at times and you want to find out what is causing it, then you may need to profile your application with a tool such as Instruments. Colin Ruffenach wrote a nice tutorial about time profiling with Instruments on Mobiletuts+.
If Instruments doesn't give you a clear answer, you may be interested in MGBenchmark, a benchmarking library developed and maintained by Mattes Groeger. This compact library lets you measure how fast your code executes and it helps you to track down the bottlenecks in your code base. It actually complements Instruments quite well so you shouldn't use one or the other. Mattes Groeger's library comes with an extensive feature set and is remarkably powerful. I highly recommend it as an alternative or complement to Instruments.
5. Stress Testing
If you're developing an application that works with lots of data, then it is important to test it with...well...lots of data! During the development of an application, it isn't always easy or possible to imagine how your users are going to use your application, but it is good to put it through its paces before releasing it. Your application may perform admirably during development and perform terribly in situations where it is flooded with data. You probably won't be able to predict, let alone test, all the circumstances in which your application will be used, but you can try to mimic common situations by creating data sets to test with.
I often create a small script or class that populates the application with test data to measure how well it performs with a lot of data. Ideally, you want to populate the application with more test data than an average user will have - to the extent that you can predict this during development. When I was developing Pixelsync, an iPad application that interfaces with Aperture and iPhoto, I created an Aperture library with close to 500,000 images. If Pixelsync performed well with a photo library of that size, I could be fairly confident that the average user wouldn't run into performance issues.
If you really are a lazy developer or you just don't have enough time, then you can also be more creative by building a robot to do the job for you.
Conclusion
Application performance remains an essential aspect of software development despite the fact that the new generation of devices are much more powerful and capable. Blocking the main thread, for example, will always result in a bad user experience no matter how capable the device is.
Comments