At each step in the development of your application, you should consider the implications of your design choices on the overall performance of your application. The operating environment for iOS applications is more constrained because of the mobile nature of iPhone and iPod touch devices. The following sections describe the factors you should consider throughout the development process.
You should be careful what work you perform from the main thread of your application. The main thread is where your application handles touch events and other user input. To ensure that your application is always responsive to the user, you should never use the main thread to perform long-running tasks or to perform tasks with a potentially unbounded end, such as tasks that access the network. Instead, you should always move those tasks onto background threads. The preferred way to do so is to wrap each task in an operation object and add it to an operation queue, but you can also create explicit threads yourself.
Moving tasks into the background leaves your main thread free to continue processing user input, which is especially important when your application is starting up or quitting. During these times, your application is expected to respond to events in a timely manner. If your application’s main thread is blocked at launch time, the system could kill the application before it even finishes launching. If the main thread is blocked at quitting time, the system could kill the application before it has a chance to write out crucial user data.
For more information about using operation objects and threads, see Concurrency Programming Guide.
Because the iOS virtual memory model does not include disk swap space, applications are somewhat more limited in the amount of memory they have available for use. Using large amounts of memory can seriously degrade system performance and potentially cause the system to terminate your application. When you design, therefore, make it a high priority to reduce the amount of memory used by your application.
There is a direct correlation between the amount of free memory available and the relative performance of your application. Less free memory means that the system is more likely to have trouble fulfilling future memory requests. If that happens, the system can always remove code pages and other nonvolatile resources from memory. However, removing those resources may be only a temporary fix, especially when those resources are needed again a short time later. Instead, minimize your memory use in the first place, and clean up the memory you do use in a timely manner.
The following sections provide more guidance on how to use memory efficiently and how to respond when there is only a small amount of available memory.
Table 8-1 lists some tips on how to reduce your application’s overall memory footprint. Starting off with a low footprint gives you more room for the data you need to manipulate.
Tip | Actions to take |
---|---|
Eliminate memory leaks. | Because memory is a critical resource in iOS, your application should not have any memory leaks. Allowing leaks to exist means your application may not have the memory it needs later. You can use the Instruments application to track down leaks in your code, both in the simulator and on actual devices. For more information on using Instruments, see Instruments User Guide. |
Make resource files as small as possible. | Files reside on the disk but must be loaded into memory before they can be used. Property list files and images are two resource types where you can save space with some very simple actions. To reduce the space used by property list files, write those files out in a binary format using the |
Use Core Data or SQLite for large data sets. | If your application manipulates large amounts of structured data, store it in a Core Data persistent store or in a SQLite database instead of in a flat file. Both Core Data and SQLite provides efficient ways to manage large data sets without requiring the entire set to be in memory all at once. The Core Data feature was introduced in iOS 3.0. |
Load resources lazily. | You should never load a resource file until it is actually needed. Prefetching resource files may seem like a way to save time, but this practice actually slows down your application right away. In addition, if you end up not using the resource, loading it simply wastes memory. |
Build your program using Thumb. | Adding the |
iOS applications use a managed memory model, whereby you must explicitly retain and release objects. Table 8-2 lists tips for allocating memory inside your program.
Tip | Actions to take |
---|---|
Reduce your use of autoreleased objects. | Objects released using the |
Impose size limits on resources. | Avoid loading large resource files when a smaller one will do. Instead of using a high-resolution image, use one that is appropriately sized for iOS-based devices. If you must use large resource files, find ways to load only the portion of the file that you need at any given time. For example, rather than load the entire file into memory, use the |
Avoid unbounded problem sets. | Unbounded problem sets might require an arbitrarily large amount of data to compute. If the set requires more memory than is available, your application may be unable to complete the calculations. Your applications should avoid such sets whenever possible and work on problems with known memory limits. |
For detailed information on how to allocate memory in iOS applications, and for more information on autorelease pools, see “Cocoa Objects” in Cocoa Fundamentals Guide.
The processors found in iOS-based devices are capable of performing floating-point calculations in hardware. If you have an existing program that performs calculations using a software-based fixed-point math library, you should consider modifying your code to use floating-point math instead. Hardware-based floating-point computations are typically much faster than their software-based fixed-point equivalents.
Important: Of course, if you build your application for arm6 and your code does use floating-point math extensively, remember to compile that code without the -mthumb
compiler option. The Thumb option can reduce the size of code modules, but it can also degrade the performance of floating-point code. If you build your application for arm7, you should always enable the Thumb option.
In iOS 4 and later, you can also use the functions of the Accelerate framework to perform complex mathematical calculations. This framework contains high-performance vector-accelerated libraries for digital signal processing and linear algebra mathematics. You can apply these libraries to problems involving audio and video processing, physics, statistics, cryptography, and complex algebraic equations.
Power consumption on mobile devices is always an issue. The power management system in iOS conserves power by shutting down any hardware features that are not currently being used. In addition to avoiding CPU-intensive operations or operations that involve high graphics frame rates, you can help improve battery life by optimizing your use of the following features:
The CPU
Wi-Fi, Bluetooth, and baseband (EDGE, 3G) radios
The Core Location framework
The accelerometers
The disk
The goal of your optimizations should be to do the most work you can in the most efficient way possible. You should always optimize your application’s algorithms using Instruments. But it is important to remember that even the most optimized algorithm can still have a negative impact on a device’s battery life. You should therefore consider the following guidelines when writing your code:
Avoid doing work that requires polling. Polling prevents the CPU from going to sleep. Instead of polling, use the NSRunLoop
or NSTimer
classes to schedule work as needed.
Leave the idleTimerDisabled
property of the shared UIApplication
object set to NO
whenever possible. The idle timer turns off the device’s screen after a specified period of inactivity. If your application does not need the screen to stay on, let the system turn it off. If your application experiences side effects as a result of the screen turning off, you should modify your code to eliminate the side effects rather than disable the idle timer unnecessarily.
Coalesce work whenever possible, to maximize idle time. It takes more power to do work periodically over an extended period of time than it does to perform the same amount of work all at once. Performing work periodically prevents the system from powering down hardware over a longer period of time.
Avoid over-accessing the disk. For example, if your application saves state information to the disk, do so only when that state information changes and coalesce changes whenever possible to avoid writing small changes at frequent intervals.
Do not draw to the screen faster than needed. Drawing is an expensive operation when it comes to power. Do not rely on the hardware to throttle your frame rates. Draw only as many frames as your application actually needs.
If you use the UIAccelerometer
class to receive regular accelerometer events, disable the delivery of those events when you do not need them. Similarly, set the frequency of event delivery to the smallest value that is suitable for your needs. For more information, see Event Handling Guide for iOS.
The more data you transmit to the network, the more power must be used to run the radios. In fact, accessing the network is the most power-hungry operation you can perform and should be minimized by following these guidelines:
Connect to external network servers only when needed, and do not poll those servers.
When you must connect to the network, transmit the smallest amount of data needed to do the job. Use compact data formats and do not include excess content that will simply be ignored.
Transmit data in bursts rather than spreading out transmission packets over time. The system turns off the Wi-Fi and cell radios when it detects a lack of activity. When it transmits data over a longer period of time, your application uses much more power than when it transmits the same amount of data in a shorter amount of time.
Connect to the network using the Wi-Fi radios whenever possible. Wi-Fi uses less power and is preferred over the baseband radios.
If you use the Core Location framework to gather location data, disable location updates as soon as you can and set the distance filter and accuracy levels to appropriate values. Core Location uses the available GPS, cell, and Wi-Fi networks to determine the user’s location. Although Core Location works hard to minimize the use of these radios, setting the accuracy and filter values gives Core Location the option to turn off hardware altogether in situations where it is not needed. For more information, see Location Awareness Programming Guide.
The Instruments application includes several instruments for gathering power-related information. You can use these instruments to gather general information about power consumption and to gather specific measurements for hardware such as the Wi-Fi and Bluetooth radios, GPS receiver, display, and CPU. For more information about using these instruments, see Instruments User Guide.
iOS comes with several applications for tuning the performance of your application. Most of these tools run on Mac OS X and are suitable for tuning some aspects of your code while it runs in the simulator. For example, you can use the simulator to eliminate memory leaks and make sure your overall memory usage is as low as possible. You can also remove any computational hotspots in your code that might be caused by an inefficient algorithm or a previously unknown bottleneck.
After you have tuned your code in the simulator, you should then use the Instruments application to further tune your code on a device. Running your code on an actual device is the only way to tune your code fully. Because the simulator runs in Mac OS X, it has the advantage of a faster CPU and more usable memory, so its performance is generally much better than the performance on an actual device. And using Instruments to trace your code on an actual device may point out additional performance bottlenecks that need tuning.
For more information on using Instruments, see Instruments User Guide.
When creating files or writing out file data, keep the following guidelines in mind:
Minimize the amount of data you write to the disk. File operations are relatively slow and involve writing to the Flash disk, which has a limited lifespan. Some specific tips to help you minimize file-related operations include:
Write only the portions of the file that changed, but aggregate changes when you can. Avoid writing out the entire file just to change a few bytes.
When defining your file format, group frequently modified content together so as to minimize the overall number of blocks that need to be written to disk each time.
If your data consists of structured content that is randomly accessed, store it in a Core Data persistent store or a SQLite database. This is especially important if the amount of data you are manipulating could grow to be more than a few megabytes in size.
Avoid writing cache files to disk. The only exception to this rule is when your application quits and you need to write state information that can be used to put your application back into the same state when it is next launched.
The networking stack in iOS includes several interfaces over the radio hardware of iPhone and iPod touch devices. The main programming interface is the CFNetwork framework, which builds on top of BSD sockets and opaque types in the Core Foundation framework to communicate with network entities. You can also use the NSStream
classes in the Foundation framework and the low-level BSD sockets found in the Core OS layer of the system.
The following sections provide iOS-specific tips for developers who need to incorporate networking features into their applications. For information about how to use the CFNetwork framework for network communication, see CFNetwork Programming Guide and CFNetwork Framework Reference. For information about using the NSStream
class, see Foundation Framework Reference.
When implementing code to receive or transmit across the network, remember that doing so is one of the most power-intensive operations on a device. Minimizing the amount of time spent transmitting or receiving helps improve battery life. To that end, you should consider the following tips when writing your network-related code:
For protocols you control, define your data formats to be as compact as possible.
Avoid communicating using chatty protocols.
Transmit data packets in bursts whenever you can.
The cellular and Wi-Fi radios are designed to power down when there is no activity. Doing so can take several seconds though, depending on the radio. If your application transmits small bursts of data every few seconds, the radios may stay powered up and continue to consume power, even when they are not actually doing anything. Rather than transmit small amounts of data more often, it is better to transmit a larger amount of data once or at relatively large intervals.
When communicating over the network, it is also important to remember that packets can be lost at any time. When writing your networking code, you should be sure to make it as robust as possible when it comes to failure handling. It is perfectly reasonable to implement handlers that respond to changes in network conditions, but do not be surprised if those handlers are not called consistently. For example, the Bonjour networking callbacks may not always be called immediately in response to the disappearance of a network service. The Bonjour system service does immediately invoke browsing callbacks when it receives a notification that a service is going away, but network services can disappear without notification. This might occur if the device providing the network service unexpectedly loses network connectivity or the notification is lost in transit.
If your application accesses the network using the Wi-Fi radios, you must notify the system of that fact by including the UIRequiresPersistentWiFi
key in the application’s Info.plist
file. The inclusion of this key lets the system know that it should display the network selection panel if it detects any active Wi-Fi hot spots. It also lets the system know that it should not attempt to shut down the Wi-Fi hardware while your application is running.
To prevent the Wi-Fi hardware from using too much power, iOS has a built-in timer that turns off the hardware completely after 30 minutes if no application has requested its use through the UIRequiresPersistentWiFi
key. If the user launches an application that includes the key, iOS effectively disables the timer for the duration of the application’s life cycle. As soon as that application quits, however, the system reenables the timer.
Note: Note that even when UIRequiresPersistentWiFi
has a value of true
, it has no effect when the device is idle (that is, screen-locked). The application is considered inactive, and although it may function on some levels, it has no Wi-Fi connection.
For more information on the UIRequiresPersistentWiFi
key and the keys of the Info.plist
file, see “The Information Property List.”
If the device is in airplane mode when your application launches, the system may display a panel to notify the user of that fact. The system displays this panel only when all of the following conditions are met:
Your application’s information property list (Info.plist
) file contains the UIRequiresPersistentWiFi
key and the value of that key is set to true.
Your application launches while the device is currently in airplane mode.
Wi-Fi on the device has not been manually reenabled after the switch to airplane mode.
Last updated: 2010-06-30