- Creating New Projects
- Building Hello World the Template Way
- Using the Simulator
- The Minimalist Hello World
- Converting Interface Builder Files to Their Objective-C Equivalents
- Using the Debugger
- Memory Management
- Recipe: Using Instruments to Detect Leaks
- Recipe: Using Instruments to Monitor Cached Object Allocations
- Analyzing Your Code
- Building for the iOS Device
- Detecting Simulator Builds with Compile-Time Checks
- Performing Runtime Compatibility Checks
- Pragma Marks
- Preparing for Distribution
- Over-the-Air Ad Hoc Distribution
- Submitting to the App Store
- Summary
Recipe: Using Instruments to Detect Leaks
Instruments plays an important role in tuning your applications. It offers a suite of tools that lets you monitor and evaluate performance. For example, its leak detection lets you track, identify, and resolve memory leaks within your program. Recipe 3-1 shows an application that creates two kinds of leaks on demands: one created by using CF bridging without a proper release, the other by introducing a strong reference cycle that cannot be resolved by ARC at the termination of its method.
To see Instruments in action, load the sample project for Recipe 3-1. Choose one of the simulator options as your destination from the leftmost pop-up in the toolbar at the top of your workspace, just to the right of the Run and Stop buttons. Then click and hold the Run button until the pop-up shown in Figure 3-12 appears. Choose Profile and then agree to whatever impediments Xcode throws in your direction (if any), such as stopping any currently running application, and so on.
Figure 3-12. Select Profile from the Run button’s pop-up.
Instruments launches and asks you to select a Trace Template. Choose iOS Simulator > Leaks and then click Profile. Instruments opens a new profiling window, launches the application in the simulator, and starts running. Click the Stop button at the top-left of the Instruments window. There are some adjustments you’ll want to make.
In the left-hand column, under the individual Instruments traces, you’ll see an item labeled “Allocations.” It is just below a slider and just above the Heapshot Analysis. This is a pop-up, as indicated by the arrows to its right. Use the pop-up to change from Allocations to Leaks.
With Leaks selected, the first item is now Snapshots. Change the Snapshot Interval from 10 seconds to 1. This lets you see updates in “real” time; even so, be patient. Instruments detects leaks during its snapshots, with a slight lag after performing the snapshot.
You are now ready to start a fresh trace. Click Record. The application relaunches in the simulator. With Instruments and the simulator both running, click one of the two buttons in the title bar to leak memory:
- The CF Bridging button leaks a simple 16-byte NSArray.
- The Retain Cycle button leaks two 16-byte NSArray objects that are connected to each other via a retain cycle, for a total of 32 bytes.
Memory leaks appear in Instruments as orange markers, scaled to the size of the leaks. The Leaked Blocks pane appears at the bottom of the window, as shown in Figure 3-13, once you click the Leaks trace row at the top of the window.
Figure 3-13. Instruments tracks leaks created by memory blocks that cannot be addressed or recovered by your code.
The trace shown in Figure 3-13 presents two leak events. The first orange marker corresponds to tapping the Retain Cycle button; the second to CF Bridging. The responsible frame for the first leak is shown to be the leakArrayRetainCycle method. A stack trace appears in the extended detail pane on the right side of the view. This pane is shown or hidden using the rightmost of the three View buttons at the top toolbar of the Instruments window. My “Hello World” code is noted to be the responsible library for both of the leaks, allowing me to further recognize that the leaked memory originated in my code.
Recipe 3-1. Creating Programmatic Leaks
- (void) leakArrayRetainCycle { NSMutableArray *array1 = [NSMutableArray array]; NSMutableArray *array2 = [NSMutableArray array]; [array1 addObject:array2]; [array2 addObject:array1]; } - (void) leakArrayCFBridge { NSArray *array = [NSArray arrayWithObjects: @"Hello", @"World", nil]; CFArrayRef leakyRef = (__bridge_retained CFArrayRef) array; leakyRef = NULL; }