Professional Documents
Culture Documents
19/12/16, 1(56 AM
This is a post by iOS Tutorial Team Member Marcelo Fabri, an iOS developer working at Movile. Check out his personal website or find him
on Twitter or on Google+.
When developing an iOS app, its critical that your app has good
performance. Your users expect it, and it will hurt your reviews if
your app appears unresponsive or slow.
However, due to the limitations of iOS devices this can sometimes be quite hard to get working quite right. Theres a lot to
keep in mind during development, and its easy to forget the performance impact of your decisions.
That is exactly why I wrote this article! This article gathers together 25 tips and tricks that you can use to improve the performance
of your apps, in the form of a handy checklist.
Note: Before optimizing any code, make sure theres a problem to be solved! Dont get sucked into the mistake
of pre-optimizing your code. Use Instruments frequently to profile your code and uncover any areas that need
improvement. Matt Galloway wrote a great tutorial about using Instruments to optimize your code.
Also, keep in mind that some of the tips offered in this article offered are trade-offs; the suggested improvements will make your code faster or more efficient, but they may require a lot of work to implement, or make
your code more complicated, so choose wisely!
Table of Contents
The tips below are categorized into three different levels beginner, intermediate and advanced:
Beginner
These are tips that youll always want to implement in any app you develop.
1. Use ARC to Manage Memory
2. Use a reuseIdentifier Where Appropriate
3. Set Views as Opaque When Possible
4. Avoid Fat XIBs
5. Dont Block the Main Thread
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 1 of 17
19/12/16, 1(56 AM
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 2 of 17
19/12/16, 1(56 AM
To use reuseIdentifiers, call this method from your data source object when asked to provide a new cell for the table
view:
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
This method dequeues an existing cell if one is available, or creates a new one if necessary using the previously registered nib file or class. If no cell is available for reuse, and you did not register a class or nib file, this method returns
nil.
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 3 of 17
19/12/16, 1(56 AM
On relatively static screens, setting the opaque property wont be a big deal. However, if your view is embedded in a
scroll view, or is part of a complex animation, not setting this property will definitely impact the performance of your
app!
You can also use the Debug\Color Blended Layers option in the simulator to see visually what views are not set as
opaque. Your goal should be to make as many of your views opaque as possible!
4) Avoid Fat XIBs
Storyboards, introduced in iOS 5, are quickly replacing XIBs. However, XIBs are still useful in some cases. If you need to target preiOS 5 devices, or you have a custom reusable view, then you cant
really avoid them.
If youre forced into using XIBs, make them as uncomplicated as
possible. Try to create one XIB per view controller, and if possible,
break out a view controllers view hierarchy into separate XIBs.
Note that when you load a XIB into memory, all of its contents
are loaded into memory, including any images. If you have a view
youre not using immediately, then youre wasting precious memory. Its worth noting that this wont happen with storyboards,
since a storyboard will only instantiate a view controller when its
needed.
When you load a XIB, any image files are cached, along with
sound files if youre developing for OS X. Apples documentation has this to say:
When you load a nib file that contains references to image or sound resources, the nib-loading code reads the
actual image or sound file into memory and and caches it. In OS X, image and sound resources are stored in
named caches so that you can access them later if needed. In iOS, only image resources are stored in named
caches. To access images, you use the imageNamed: method of NSImage or UIImage, depending on your
platform.
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 4 of 17
19/12/16, 1(56 AM
Apparently, this also happens when using storyboards; however, I wasnt able to find anything supporting this claim.
If you know anything about this behavior, please drop me a line!
Want to learn more about storyboards? Check out Matthijs Hollemans Beginning Storyboards in iOS 5 Part 1 and Part
2.
5) Dont Block the Main Thread
You should never do any heavy lifting on the main thread. This is because UIKit does all of its own work on the main thread, such as
drawing, managing touches, and responding to input.
The risk of doing all of your apps work on the main thread is that if
your code does block this thread, your app will appear unresponsive.
Thats a quick route to one-star reviews on the App Store! :]
Most cases of blocking the main thread occur when your app is performing an I/O operation which involves any task that needs to read
or write from an external source, such as the disk or the network.
You can perform network tasks asynchronously by using this method
on NSURLConnection:
Dont Block the Main Thread.
});
See how theres a nested dispatch_async inside the first one? Thats because any UIKit related code needs to be executed on the main thread.
Curious about the finer details of NSOperation or GCD? Take a look at Ray Wenderlichs Multithreading and Grand
Central Dispatch on iOS for Beginners tutorial, as well as Soheil Azarpours How To Use NSOperations and NSOperationQueues tutorial.
6) Size Images to Image Views
If youre displaying an image from the apps bundle in a UIImageView, make sure that the image and the UIImageView
are same size. Scaling images on the fly can be expensive, especially if your UIImageView is embedded in a
UIScrollView.
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 5 of 17
19/12/16, 1(56 AM
Happily,
theres a document
named Collections Programming Topics on Apples Developer Library that explains in detail the differences between
the available classes, as well as which situations suit each class. Its a must read document for anyone looking to work
with collections.
TLDR? Heres a quick synopsis of the most common collection types:
Arrays: Ordered list of values. Quick lookup by index, slow to lookup by value, slow to insert/delete.
Dictionaries: Store key/value pairs. Quick lookups by key.
Sets: Unordered list of values. Quick lookup by value, quick to insert/delete.
Page 6 of 17
19/12/16, 1(56 AM
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 7 of 17
19/12/16, 1(56 AM
return request;
Note that you can fetch a URL request via NSURLConnection, but AFNetworking can fetch it as well; that way you
dont need to change all your networking code because of this tip! :]
If want to know more about HTTP caching, NSURLCache, NSURLConnection and friends, be sure to take a look at the
NSURLCache entry on NSHipster.
If you need to cache other things that dont involve HTTP requests, then NSCache is your go-to guy.
NSCache looks and behaves like an NSDictionary, but it automatically removes its contents when the system needs to
reclaim memory. Mattt Thompson wrote this amazing post on NSHipster about it.
Interested in learning more about HTTP caching? Google has a best-practices document on HTTP caching that is a recommended read.
11) Consider Drawing
There are several ways to make great-looking buttons in iOS. You
can use full sized images, resizable images, or you could go the
distance and draw it manually using CALayer, CoreGraphics or
even OpenGL.
Of course, theres different levels of complexity with each of these
approaches, as well as differences in their performance. Theres
an awesome post about iOS graphics performance here which is
well worth a read. Andy Matuschak, who is a member of the UIKit
team over at Apple, commented on the post, and theres some
great insight into the different approaches and their performance
trade-offs.
The short story is that using pre-rendered images is faster, beConsider Drawing.
cause iOS doesnt have to create an image and draw shapes on it
to finally draw into than screen (the image is already created!).
The problem is that you need to put all those images in your
apps bundle, increasing its size. Thats why using resizable images is so great: you save space by removing wasted
image space that iOS can repeat for you. You also dont need to generate different images for different elements (e.g.
buttons).
However, by using images you lose the ability to tweak your images by code, needing to regenerate them every and
putting them into the app again and again. That can be a slow process. Another point is that if you have an animation
or just a lot of images with slightly changes (they can have multiple overlay color, for example), youll have to embed a
lot of images, growing the apps bundle size.
To summarize, you need to think whats most important to you: drawing performance or apps size. Generally both
are important, so youll use both approaches in the same project!
12) Handle Memory Warnings
iOS notifies all running apps when system memory is running low. Heres what the official Apple documentation says
about handling the low memory warning:
If your app receives this warning, it must free up as much memory as possible. The best way to do this is to re-
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 8 of 17
19/12/16, 1(56 AM
move strong references to caches, image objects, and other data objects that can be recreated later.
Fortunately, UIKit provides several ways to receive these low-memory warnings, including the following:
Implement the applicationDidReceiveMemoryWarning: method of your app delegate.
Override didReceiveMemoryWarning in your custom UIViewController subclass.
Register to receive the UIApplicationDidReceiveMemoryWarningNotification notification.
Upon receiving any of these warnings, your handler method should respond by immediately freeing up any unnecessary memory.
For example, the default behavior of UIViewController is to purge its view if that view is not currently visible; subclasses can supplement the default behavior of their parent class by purging additional data structures. An app that maintains a cache of images might respond by releasing any images that are not currently on-screen.
Its very important to release all memory possible once you receive a memory warning. Otherwise, you run the risk of
having your app killed by the system.
However, be careful when you start culling objects to free up memory, as youll need to make sure they can be recreated later. Be sure to use the Simulate memory warning feature on the iOS simulator to test this condition while you
are developing your app!
13) Reuse Expensive Objects
Some objects are very slow to initialize NSDateFormatter and
NSCalendar are two examples. However, you cant always avoid using them, such as when parsing dates from a JSON/XML response.
To avoid performance bottlenecks when working with these objects, try to reuse these objects if at all possible. You can do this by
either adding a property to your class, or by creating a static
variable.
Note that if you choose the second approach, the object will remain in memory while your app is running, much like a singleton.
The code below demonstrates making a property that lazy-loads a
date formatter. The first time it is called, it creates a new date formatter. Future calls will just return the already created instance:
Page 9 of 17
19/12/16, 1(56 AM
// no property is required anymore. The following code goes inside the implementation
(.m)
- (NSDateFormatter *)formatter {
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_formatter = [[NSDateFormatter alloc] init];
_formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy"; // twitter date format
});
return formatter;
}
As our reader said, this will ensure its initialized only once, and if a second thread calls the method while the block is running, it will pause until the block has completed.
Also remember that setting a NSDateFormatters date format is almost as slow as creating a new one! Therefore, if
you frequently need to deal with multiple date formats in your app, your code may benefit from initially creating, and
reusing, multiple NSDateFormatter objects.
14) Use Sprite Sheets
So youre a game developer? Then sprite sheets are one of your
best friends. Sprite sheets make drawing faster and can even consume less memory than standard screen drawing methods.
There are two awesome sprite sheet tutorials about sprite sheets
on this site:
1. How To Use Animations and Sprite Sheets in Cocos2D
2. How to Create and Optimize Sprite Sheets in Cocos2D with
Texture Packer and Pixel Formats
The second tutorial covers pixel formats in detail, which can have
a measurable impact on a games performance.
If youre not yet familar with sprite sheets, then a great introduction can be found in SpriteSheets The Movie, Part 1 and Part 2.
The author of these videos is Andreas Lw, the creator of Texture
Packer, one of the most popular tools for creating sprite sheets.
Besides using sprite sheets, several tips already covered here can
be applied to games as well. For example, if your game has many
sprites, such as enemies or projectiles in your standard shootem-up, then you can reuse sprites instead of recreating them every time.
15) Avoid Re-Processing Data
Many apps make calls for data from remote servers to get information the app requires to function. This data usually
comes across in JSON or XML format. Its important to try and use the same data structure at both ends when requesting and receiving the data.
Why? Manipulating data in memory to fit your data structures can be expensive.
For example, if you need to display the data in a table view, it would be best to request and receive the data in an arhttps://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 10 of 17
19/12/16, 1(56 AM
ray format to avoid any intermediate manipulation of the data to make it fit the data structure that youre using in
your app.
Similarly, if your application depends on accessing specific values by their keys, then youll probably want to request
and receive a key/value pair dictionary.
By getting the data in the right format the first time, youll avoid a lot of re-processing in your app to make the data fit
your chosen structure.
16) Choose the Right Data Format
There are multiple ways you can transfer data to your app from a
web service, but the most common two are JSON and XML. You
want to make sure you choose the right one for your app.
JSON is faster to parse, and is generally smaller than XML, which
means less data to transfer. And since iOS 5, theres built-in JSON
deserialization so its easy to use as well.
However, one advantage XML has is that if you use the SAX parsing method, you can work with XML data as you read it off the
wire, instead of having to wait for the entire data to arrive before
you parse it like JSON. This can give you increased performance
and reduced memory consumption when you are dealing with
very large sets of data.
Like many other things in iOS coding, theres at least two different
ways to place a background image on your view:
1. You can set your views background color to a color created with UIColors colorWithPatternImage.
2. You can add a UIImageView subview to the view.
If you have a full size background image, then you should definitely use a UIImageView because UIColors colorWithPatternImage was made to create small pattern images that will be repeated, and not large images size. Using UIImageView will save a lot of memory in this case.
Page 11 of 17
19/12/16, 1(56 AM
powers Apples Safari app. This is down to the restricted use of Webkits Nitro Engine, which features JIT compilation.
So to get the best performance, youll need to tweak your HTML a bit. The first thing you should do is get rid of as
much Javascript as you can, which includes avoiding large frameworks such as jQuery. It can sometimes be a lot
faster to work with vanilla Javascript instead of relying on frameworks to do the work for you.
Also follow the practice of loading your Javascript files asynchronously where possible especially when they dont directly impact the behavior of the page, such as analytics scripts.
And finally always be aware of the images that you are using, and keep images right-sized for your purposes. As
mentioned earlier in this tutorial, make use of sprite sheets wherever possible to conserve memory and improve
speed.
For more information, be sure to take a look at WWDC 2012 session #601 Optimizing Web Content in UIWebViews
and Websites on iOS.
19) Set the Shadow Path
So you need to add a shadow to a view, or to a layer. How should you handle this?
Most developers would just add the QuartzCore framework to their project, and then add the following code:
#import <QuartzCore/QuartzCore.h>
Page 12 of 17
19/12/16, 1(56 AM
If the cell shows content that comes from the web, be sure to make those calls asynchronously and cache the
responses.
Use shadowPath to set up shadows.
Reduce the number of subviews.
Do as little work as possible in cellForRowAtIndexPath:. If you need to do some work, do it only once and cache
the results.
Use the appropriate data structure to hold the information you need. Different structures have different costs
for different operations.
Use rowHeight, sectionFooterHeight and sectionHeaderHeight to set constant heights instead of asking the
delegate.
21) Choose Correct Data Storage Option
What are your options when it comes to storing and
reading large data sets?
You have several options, including:
Store them using NSUserDefaults
Save to a structured file in XML, JSON, or Plist
format
Archive using NSCoding
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 13 of 17
19/12/16, 1(56 AM
Note: The watchdog doesnt run while debugging with Xcode, so be sure to test your app with your device disconnected from Xcode while testing for launch performance.
This method looks in the system caches for an image object with the specified name and returns that object if it
exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 14 of 17
19/12/16, 1(56 AM
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 15 of 17
19/12/16, 1(56 AM
Marcelo Fabri
Marcelo is a CS student at Unicamp. At his little spare time, tries to make an indie game,
and watches (a lot) of tv shows. He is also available to contract work. You can reach him
via LinkedIn, email or his personal site.
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 16 of 17
19/12/16, 1(56 AM
https://www.raywenderlich.com/31166/25-ios-app-performance-tips-tricks
Page 17 of 17