Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Cocoa Memory Management


Rules of Retention and Release

Once you know how to retain and release Cocoa objects, you need to become familiar on when to use the [retain], [release], and [autorelease] messages. Incorrect use of these messages can result in memory leaks or the dreaded SIG_SEGV and EXC_BAD_ACCESS fatal errors. These rules may help:

  • If you instantiated an object using [alloc] or [copy], dispose of the object using either [release] or an [autorelease].
  • If you instantiated an object using a convenience method, the object is already slated for autorelease. Do not send a [release] or an [autorelease] message to this object.
  • If you send a [retain] message to the object, send a [release] message to cancel the retention.
  • If you received an object as a result of a method call, always assume that the object is valid within the scope of your calling method. If you want to extend the object's validity beyond the scope of your calling method, send a [retain] message to that object.
  • Use the [release] message whenever possible for performance reasons. If you are returning an object as part of your method call, use the [autorelease] message.
  • Retain and release the object to prevent the object from being accidentally eliminated as a side effect of certain Cocoa operations such as NSLog().
  • Balance all [retain] messages with an equal number of [release] and [autorelease] messages.
  • Never send a [dealloc] message to the object. Though this may also dispose of the object, it does so regardless of the current reference count. Other objects that have retained the object you've just deallocated are left with invalid references.

Designing Accessors and Modifiers

Accessor and modifier methods let other objects access and modify an object's internal properties. If the property itself happens to contain a Cocoa object, other Cocoa objects may try to retain and release that property value. This is where memory management becomes a factor in their implementation. Because accessors and modifiers are some of the most frequently called methods, be sure that these methods perform as efficiently as possible.

I design accessor and modifier methods in five different ways. To illustrate each design variant, I use the generic Cocoa class in Listing Three.

Listing Three

@interface anObj:NSObject
{
  NSObject    *theProp
}
-(NSObject  *) getObject;
-(void) setObject:(NSObject *)newObj;
@end

The class has an accessor method named getObj and a modifier named setObject. The internal property used to store a Cocoa object is theProp. Listing Four is a basic design of an accessor and modifier method. Here, the getObject accessor simply returns a reference to theProp. The setObject modifier first sends a [retain] message to newObj to retain the new object. It then sends a [release] message to theProp to dispose of the object stored in that property. It then updates theProp with the object contained in newObj.

Listing Four

-(void) setObject:(NSObject *)newObj
{
[newObj retain];
[theObj release];
theProp = newObj;
}
-(NSObject *)getObject
{
return (theProp);
}

In most situations, this basic accessor and modifier implementation is sufficient. However, there are design variants that provide some performance advantages in certain design scenarios. For instance, if the calling method maintains its own autorelease pool, I use the getObject accessor in Listing Five. This accessor ensures that the returned object stored in theProp is automatically placed in the caller's autorelease pool.

Listing Five

-(NSObject *) getObject
{
return ([[theProp retain] autorelease]);
}

Listing Six is a faster variant of the setObject modifier.

Listing Six

-(void) setObject:(NSObject *)newObj
{
   if (theProp != newObj)
   {
         [newObj retain];
         [theProp release];
         theProp = newObj;
   }
}

Here, the argument newObj is compared with the property theProp. If both objects are different, the modifier retains newObj and releases theProp. Only then does it update theProp with newObj. By first comparing newObj and theProp, I avoid the unnecessary process of retaining and releasing the objects involved. I also avoid updating theProp if both the property and argument already contain the same object.

Listing Seven is a third variation of the setObject modifier.

Listing Seven

-(void) setObject:(NSObject *)newObj
{
   if (theProp != newObj)
   {
   [theProp autorelease];
   theProp = [newObj retain];
   }
}

Here, an [autorelease] message is first sent to theProp. Afterwards, a [retain] message is sent to newObj, which is then assigned to theProp. I use this variant when my calling method has stored the previous value of theProp locally (see Listing Eight). Here, the current object stored in theProp is stored in the local theObj. A new object is then assigned to theProp using the [setObject] modifier. For the comparison to work, theObj needs to remain valid after the modifier is invoked. If a [release] message is sent to theProp instead of the [autorelease] message, the object stored in theObj may get eliminated, causing the if() construct to fail with either a SIG_SEGV or EXC_BAD_ACCESS error.

Listing Eight

NSObject *theObj;

theObj = [anObj getObject];
[anObj setObject:[NSObject new]];

if (theObj == [anObj getObject)
   NSLog(@"Both objects are the same");
else
   NSLog(@"Both objects are different");

Listing Nine is a variation of the setObject modifier.

Listing Nine

-(void) setObject:(NSObject *)newObj
{
   [theProp autorelease];
   theProp = [newObj retain];
}

This modifier is a faster variant of the one back in Listing Seven. It omits the comparison check used to see theProp already has the same object as newObj. I use this variant if and only if I know that newObj will always be different from theProp.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.