Home > Articles > Programming > C/C++

Objective-C Boot Camp

This chapter is from the book

Simple Memory Management

Memory management comes down to two simple rules. At creation, every object has a retain count of 0. At release, every object has (or, more accurately, is about to have) a retain count of 0. It is up to you as a developer to manage an object’s retention over its lifetime. You should ensure that it moves from start to finish without being prematurely released and guarantee that it does finally get released when it is time to do so. Complicating matters is Objective-C’s autorelease pool. If some objects are autoreleased and others must be released manually, how do you best control your objects? Here’s a quick-and-dirty guide to getting your memory management right.

Creating Objects

Any time you create an object using the alloc/init pattern, you build it with a retain count of 1. It doesn’t matter which class you use or what object you build, alloc/init produces a +1 count.

id myObject = [[SomeClass alloc] init];

For locally scoped variables, if you do not release the object before the end of a method, the object leaks. Your reference to that memory goes away, but the memory itself remains allocated. The retain count remains at +1.

- (void) leakyMethod
{
   // This is leaky
    NSArray *array = [[NSArray alloc] init];
}

The proper way to use an alloc/init pattern is to create, use, and then release. Releasing brings the retain count down to 0. When the method ends, the object is deallocated.

- (void) properMethod
{
    NSArray *array = [[NSArray alloc] init];
    // use the array here
    [array release];
}

Autorelease objects do not require an explicit release statement for locally scoped variables. (In fact, avoid doing so to prevent double-free errors that will crash your program.) Sending the autorelease message to an object marks it for autorelease. When the autorelease pool drains at the end of each event loop, it sends release to all the objects it owns.

- (void) anotherProperMethod
{
    NSArray *array = [[[NSArray alloc] init] autorelease];
    // This won't crash the way release would
    printf("Retain count is %d\n", [array retainCount]);
    // use the array here
}

By convention, object-creation class methods return an autoreleased object. The NSArray class method array returns a newly initialized array that is already set for autorelease. The object can be used throughout the method, and its release is handled when the autorelease pool drains.

- (void) yetAnotherProperMethod
{
    NSArray *array = [NSArray array];
    // use the array here
}

At the end of this method, the autoreleased array can return to the general memory pool.

Creating Autoreleased Objects

As a rule, whenever you ask another method to create an object, it’s good programming practice to return that object autoreleased. Doing so consistently lets you follow a simple rule: “If I didn’t allocate it, then it was built and returned to me as an autorelease object.”

- (Car *) fetchACar
{
    Car *myCar = [[Car alloc] init];
    return [myCar autorelease];
}

This holds especially true for class methods. By convention, all class methods that create new objects return autorelease objects. These are generally referred to as “convenience methods.” Any object that you yourself allocate is not set as autorelease unless you specify it yourself.

// This is not autoreleased
Car *car1 = [[Car alloc] init];

// This is autoreleased
Car *car2 = [[[Car alloc] init] autorelease];

// By convention, this *should* be an autoreleased object
Car *car3 = [Car car];

To create a convenience method at the class level, make sure to define the class with the + prefix (instead of -) and to return the object after sending autorelease to it:

+ (Car *) car
{
    return [[[Car alloc] init] autorelease];
}

Autorelease Object Lifetime

So how long can you use an autorelease object? What guarantees do you have? The hard-and-fast rule is that the object is yours until the next item in the event loop gets processed. The event loop is triggered by user touches, by button presses, by “time passed” events, and so forth. In human reckoning, these times are impossibly short; in the iOS SDK device’s processor frame of reference, they’re quite large. As a more general rule, you can assume that an autoreleased object should persist throughout the duration of your method call.

Once you return from a method, guarantees go out the window. When you need to use an array beyond the scope of a single method or for extended periods of time (for example, you might start a custom run-loop within a method, prolonging how long that method endures), the rules change. You must retain autorelease objects to increase their count and prevent them from getting deallocated when the pool drains; when the autorelease pool calls release on their memory, they’ll maintain a count of at least +1.

Never rely on an object’s retainCount to keep track of how often it has already been retained. If you want to make absolutely sure you own an object, retain it, use it, and then release it when you’re done. If you’re looking at anything other than your own object’s relative retain counts and matching releases, you’re going to run into systemic development errors.

Retaining Autorelease Objects

You can send retain to autorelease objects just like any other object. Retaining objects set to autorelease allows them to persist beyond a single method. Once retained, an autorelease object is just as subject to memory leaks as one you created using alloc/init. For example, retaining an object that’s scoped to a local variable might leak, as shown here:

- (void)anotherLeakyMethod
{
    // After returning, you lose the local reference to
    // array and cannot release.
    NSArray *array = [NSArray array];
    [array retain];
}

Upon creation, array has a retain count of +1. Sending retain to the object brings that retain count up to +2. When the method ends and the autorelease pool drains, the object receives a single release message; the count returns to +1. From there, the object is stuck. It cannot be deallocated with a +1 count, and with no reference left to point to the object, it cannot be sent the final release message it needs to finish its life cycle. This is why it’s critical to build references to retained objects.

By creating a reference, you can both use a retained object through its lifetime and be able to release it when you’re done. Set references via an instance variable (preferred) or a static variable defined within your class implementation. If you want to keep things simple and reliable, use retained properties built from those instance variables. The next section shows you how retained properties work and demonstrates why they provide the solution of choice for developers.

Retained Properties

Retained properties hold onto data that you assign to them and properly relinquish that data when you set a new value. Because of this, they tie in seamlessly to basic memory management. Here’s how you create and use retained properties in your iOS applications.

First, declare your retained property in the class interface by including the retain keyword between parentheses:

@property (retain) NSArray *colors;

Then synthesize the property methods in your implementation:

@synthesize colors;

When given the @synthesize directive, Objective-C automatically builds routines that manage the retained property. The routines automatically retain an object when you assign it to the property. That behavior holds regardless of whether the object is set as autorelease. When you reassign the property, the previous value is automatically released.

Assigning Values to Retained Properties

When working with retained properties, you need to be aware of two patterns of assignment. These patterns depend on whether or not you’re assigning an autorelease object. For autorelease-style objects, use a simple single assignment. This assignment sets the colors property to the new array and retains it:

myCar.colors = [NSArray arrayWithObjects:
    @"Black", @"Silver", @"Gray", nil];

The array is created and returned as an autorelease object with a count of +1. The assignment to the retained colors property brings the count to +2. Once the current event loop ends, the autorelease pool sends release to the array, and the count drops back to +1.

For normal (non-autorelease) objects, release the object after assigning it. Upon creation, the retain count for a normally allocated object is +1. Assigning the object to a retained property increases that count to +2. Releasing the object returns the count to +1.

// Non-autorelease object. Retain count is +1 at creation
NSArray *array = [[NSArray alloc]
    initWithObjects:@"Black", @"Silver", @"Gray", nil];

// Count rises to +2 via assignment to a retained property
myCar.colors = array;

// Now release to get that retain count back to +1
[array release];

You often see this pattern of create, assign, release in iOS development. You might use it when assigning a newly allocated view to a view controller object. Here’s an example:

UIView *mainView = [[UIView alloc] initWithFrame:aFrame];
self.view = mainView;
[mainView release];

These three steps move the object’s retain count from +1 to +2 and then back to +1.

A final count of +1 guarantees you that can use an object indefinitely. At the same time, you’re assured that the object deallocates properly when the property is set to a new value and release is called on its prior value. That release on a +1 object allows the object to deallocate.

Reassigning a Retained Property

When you’re done using a retained property, regardless of the approach used to create that object, set the property to nil or to another object. This sends a release message to the previously assigned object.

myCar.colors=nil;

If the colors property had been set to an array, as just shown, that array would automatically be sent a release message. Since each pattern of assignment produced a +1 retained object, this reassignment would send release to the +1 object. The object’s life would be over.

Avoiding Assignment Pitfalls

Within a class implementation, it’s handy to use properties to take advantage of this memory management behavior. To take advantage of this, avoid using instance variables directly. Direct assignment like this won’t retain the array or release any previous value. This is a common pitfall for new iOS developers. Remember the dot notation when accessing the instance variables.

colors = [NSArray arrayWithObjects:
     @"Black", @"Silver", @"Gray", nil];

This same caution holds true for properties defined as assign. Note the following behavior carefully. Although both

@property NSArray *colors;

and

@property (assign) NSArray *colors;

allow you to use dot notation, assignment via these properties does not retain or release objects. Assign properties expose the colors instance variable to the outside world, but they do not provide the same memory management that retain properties do.

High Retain Counts

Retain counts that go and stay above +1 do not necessarily mean you’ve done anything wrong. Consider the following code segment. It creates a view and starts adding it to arrays. This raises the retain count from +1 up to +4.

// On creation, view has a retain count of +1;
UIView *view = [[[UIView alloc] init] autorelease];
printf("Count: %d\n", [view retainCount]);

// Adding it to an array increases that retain count to +2
NSArray *array1 = [NSArray arrayWithObject:view];
printf("Count: %d\n", [view retainCount]);

// Another array, retain count goes to +3
NSArray *array2 = [NSArray arrayWithObject:view];
printf("Count: %d\n", [view retainCount]);

// And another +4
NSArray *array3 = [NSArray arrayWithObject:view];
printf("Count: %d\n", [view retainCount]);

Notice that each array was created using a class convenience method and returns an autoreleased object. The view is set as autorelease, too. Some collection classes such as NSArray automatically retain objects when you add them into an array and release them when either the object is removed (mutable objects only) or when the collection is released. This code has no leaks because every one of the four objects is set to properly release itself and its children when the autorelease pool drains.

When release is sent to the three arrays, each one releases the view, bringing the count down from +4 to +1. The final release, when the object is at +1, allows the view to deallocate when this method finishes: no leaks, no further retains, no problems.

Other Ways to Create Objects

You’ve seen how to use alloc to allocate memory. Objective-C offers other ways to build new objects. You can discover these by browsing class documentation as the methods vary by class and framework. As a rule of thumb, if you build an object using any method whose name includes alloc, new, create, or copy, you maintain responsibility for releasing the object. Unlike class convenience methods, methods that include these words generally do not return autoreleased objects.

Sending a copy message to an object, for example, duplicates it. copy returns an object with a retain count of +1 and no assignment to the autorelease pool. Use copy when you want to duplicate and make changes to an object while preserving the original. Note that for the most part, Objective-C produces shallow copies of collections like arrays and dictionaries. It copies the structure of the collection, and maintains the addresses for each pointer, but does not perform a deep copy of the items stored within.

C-Style Object Allocations

As a superset of C, Objective-C programs for the iOS SDK often use APIs with C-style object creation and management. Core Foundation (CF) is a Cocoa Touch framework with C-based function calls. When working with CF objects in Objective-C, you build objects with CFAllocators and often use the CFRelease() function to release object memory.

There are, however, no simple rules. As the following code shows, you may end up using free(), CFRelease(), and custom methods such as CGContextRelease() all in the same scope, side-by-side with standard Objective-C class convenience methods such as imageWithCGImage:. The function used to create the context object used here is CGBitmapContextCreate(), and like most Core Foundation function calls, it does not return an autoreleased object. This code snippet builds a UIImage, the iOS SDK class that stores image data.

UIImage *buildImage(int imgsize)
{
    // Create context with allocated bits
    CGContextRef context  =
        MyCreateBitmapContext(imgsize, imgsize);
    CGImageRef myRef =
        CGBitmapContextCreateImage(context);
    free(CGBitmapContextGetData(context)); // Standard C free()
    CGContextRelease(context); // Core Graphics Release
    UIImage *img = [UIImage imageWithCGImage:myRef];
    CFRelease(myRef); // Core Foundation Release
    return img;
}

Carbon and Core Foundation

Working with Core Foundation comes up often enough that you should be aware of its existence and be prepared to encounter its constructs, specifically in regard to its frameworks. Frameworks are libraries of classes you can utilize in your application.

Table 3-2 explains the key terms involved. To summarize the issue, early OS X used a C-based framework called Core Foundation to provide a transitional system for developing applications that could run on both Classic Mac systems as well as Mac OS X. Although Core Foundation uses object-oriented extensions to C, its functions and constructs are all C based, not Objective-C based.

Table 3-2. Key OS X Development Terms

Term

Definition

Foundation

The core classes for Objective-C programming, offering all the fundamental data types and services needed for Cocoa and Cocoa Touch. A section at the end of this chapter intro-duces some of the most important Foundation classes you'll use in your applications.

Core Foundation

A library of C-based classes that are based on Foundation APIs but that are implemented in C. Core Foundation uses object-oriented data but is not built using the Objective-C classes.

Carbon

An early set of libraries provided by Apple that use a proce-dural API. Carbon offered event handling support, a graphics library, and many more frameworks. Some Carbon APIs live on through Core Foundation. Carbon was introduced for the Classic Mac OS, first appearing in Mac OS 8.1.

Cocoa

Apple's collection of frameworks, APIs, and runtimes that make up the modern Mac OS X runtime system. Frameworks are primarily written in Objective-C, although some continue to use C/C++.

Cocoa Touch

Cocoa's equivalent for the iOS SDK, where the frameworks are tuned for the touch-based mobile iOS user experience. Some iOS frameworks such as Core Audio and Open GL are considered to reside outside Cocoa Touch.

Toll Free Bridging

A method of Cocoa/Carbon integration. Toll Free Bridging refers to sets of interchangeable data types. For example, Cocoa's Foundation (NSString *) object can be used interchangeably with Carbon's Core Foundation's CFStringRef. Bridging connects the C-based Core Foun-dation with the Objective-C Foundation world.

Core Foundation technology lives on through Cocoa. You can and will encounter C-style Core Foundation when programming iOS applications using Objective-C. The specifics of Core Foundation programming fall outside the scope of this chapter, however, and are best explored separately from learning how to program in Objective-C.

Deallocating Objects

iPhone devices use reference count–managed Objective-C. On the iPhone, iPod touch, and iPad, there’s no garbage collection and little likelihood there ever will be. Every object cleans up after itself. So what does that mean in practical terms? Here’s a quick rundown of how you end an object’s life, cleaning up its instance variables and preparing it for deallocation.

Instance variables must release retained objects before deallocation. You as the developer must ensure that those objects return to a retain count of 0 before the parent object is itself released. To do this, you implement dealloc, a method automatically called by the runtime system when an object is about to be released. If you use a class with object instance variables (that is, not just floats, ints, and Bools), you probably need to implement a deallocation method. The basic dealloc method structure looks like this:

- (void) dealloc
{
    // Class-based clean-up
    clean up my own instance variables here

    // Clean up superclass
    [super dealloc]
}

The method you write should work in two stages. First, clean up any instance variables from your class. Then ask your superclass to perform its cleanup routine. The special super keyword refers to the superclass of the object that is running the dealloc method. How you clean up depends on whether your instance variables are automatically retained.

You’ve read about creating objects, building references to those objects, and ensuring that the objects’ retain counts stay at +1 after creation. Now, you see the final step of the object’s lifetime, namely releasing those +1 objects so they can be deallocated.

Retained Properties

In the case of retained properties, set those properties to nil using dot notation assignment. This calls the custom setter method synthesized by Objective-C and releases any prior object the property has been set to. Assuming that prior object had a retain count of +1, this release allows that object to deallocate:

self.make = nil;

Variables

When using plain (non-property) instance variables or assign-style properties, send release at deallocation time. Say, for example, you’ve defined an instance variable called salesman. It might be set at any time during the lifetime of your object. The assignment of salesman might look like this:

// release any previous value
[salesman release];

// make the new assignment. Retain count is +1
salesman = [[SomeClass alloc] init];

This assignment style means that salesman could point to an object with a +1 retain count at any time during the object’s lifetime. Therefore, in your dealloc method, you must release any object currently assigned to salesman. You can guard this with a check if salesman is not nil, but practically, you’re free to send release to nil without consequence, so feel free to skip the check.

[salesman release];

A Sample Deallocation Method

Keeping with an expanded Car class that uses retained properties for make, model, and colors, and that has a simple instance variable for salesman, the final deallocation method would look like this. The integer year and the Boolean forSale instance variables are not objects and do not need to be managed this way.

- (void) dealloc
{
    self.make = nil;
    self.model = nil;
    self.colors = nil;
    [salesman release];
    [super dealloc];
}

Managing an object’s retain count proves key to making Objective-C memory management work. Few objects should continue to have a retain count greater than +1 after their creation and assignment. By guaranteeing a limit, your final releases in dealloc are ensured to produce the memory deallocation you desire.

Cleaning Up Other Matters

The dealloc method offers a perfect place to clean up shop. For example, you might need to dispose of an Audio Toolbox sound or perform other maintenance tasks before the class is released. These tasks almost always relate to Core Foundation, Core Graphics, Core Audio, or similar C-style frameworks.

if (snd) AudioServicesDisposeSystemSoundID(snd);

Think of dealloc as your last chance to tidy up loose ends before your object goes away forever. Whether this involves shutting down open sockets, closing file pointers, or releasing resources, use this method to make sure your code returns state as close to pristine as possible.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020