Chapter     6

Expert Section Using ARC

Believe it or not, you’re approaching the end of Part 1 in this book. So far, so good! Part 1 concludes with this Expert Section chapter. Expert Section chapters are designed to provide additional details and more in-depth coverage of a subject presented earlier in the book. In this chapter, you’ll learn some of the finer details surrounding ARC memory management. You’ll review some key points about ARC memory management and object ownership, and also learn how to use ARC with toll-free bridged objects.

ARC and Object Ownership

Recall from Chapter 4 that Objective-C code creates objects stored in dynamically allocated memory (the heap). Objects created on the heap never go out of scope, thus application memory management is required to ensure that these objects are removed from memory when no longer in use, and that a program doesn’t erroneously free objects still being used. Objective-C implements memory management using a reference counting model, whereby unique references to an object are used to determine whether or not an object is still in use. ARC automates this task by inserting code (at compile time) to properly balance retain and release messages on objects, per the reference counting model. ARC prohibits programmatic control of object life cycle. Specifically, you can’t send retain or release messages to control ownership interest in objects. Hence, it is very important to understand the rules pertaining to object ownership under ARC.

Claiming Ownership Interest in Objects

Your Objective-C code takes an ownership interest in any object that it creates using any method that has a name beginning with alloc, new, copy, or mutableCopy. The main() function shown in Listing 6-1 creates an Atom object using the alloc method, and thus claims an ownership interest in this object.

Listing 6-1.  Creating an Atom Object

int main(int argc, const char * argv[])
{
  @autoreleasepool
  {
    Atom *atom = [[Atom alloc] init];
    [atom logInfo];
  }
  
  return 0;
}

Your code can also take an ownership interest in a block object if it creates one using a copy message.

Note   A block is an implementation of a closure, a function that permits access to variables outside of their typical scope. Blocks can be dynamically allocated on the heap and are also managed by ARC, as with standard Objective-C objects. Programming with blocks will be covered in depth in Part 4 of this book.

Releasing Ownership Interest in Objects

As mentioned previously, ARC prohibits programmatic use of the release, autorelease, dealloc, or related messages on an object. Your code gives up ownership interest in an object when it performs any of the following: 1) variable reassignment, 2) nil assignment, or 3) its owner is deallocated.

Variable Reassignment

If a variable that points to a dynamically created object is changed to point to another object, the object loses an owner. At compile time, ARC inserts code to send a release message to this object. At this point, if there are no more owners of the object, it will be deallocated. Listing 6-2 illustrates an example of variable reassignment.

Listing 6-2.  Object Ownership—Variable Reassignment

Atom *myAtom = [[Atom alloc] initWithName:@"Atom 1"];
// Other code
...
myAtom = [[Atom alloc] initWithName:@"Atom 2"];

In Listing 6-2, an Atom object (let’s call it Atom 1) is created and assigned to the myAtom variable; later in the code, this variable is assigned to another Atom object (let’s call it Atom 2). Because the myAtom variable has been reassigned to Atom 2, Atom 1 loses an owner and will be deallocated if there are no other owners of this object.

nil Assignment

If the value of a variable that currently points to a dynamically created object is set to nil, the object loses an owner. Listing 6-3 illustrates an example of nil assignment.

Listing 6-3.  Object Ownership—nil Reassignment

Atom *myAtom = [[Atom alloc] init];
// Other code
...
myAtom = nil;

In Listing 6-3, an Atom object is created and assigned to the myAtom variable; later in the code, this variable is set to nil. Because the myAtom variable has been set to nil, the Atom object loses an owner. Again, ARC inserts code to send a release message to this object after the statement that sets the myAtom variable to nil.

Owner Deallocation

Owner deallocation. Now that doesn’t sound very pleasant, does it? Actually this phrase refers to object ownership and how ARC transparently manages the object life cycle of both object graphs and collections. Object-oriented programs consist of webs of interrelated objects. These objects are linked together through OOP inheritance and/or composition, collectively referred to as an object graph. In an object graph, objects contain references to other (child) objects through the principle of composition. If a (parent) object creates another (child) object, it has claimed an ownership interest in it. In Chapter 4, you created a program with an object graph consisting of an OrderEntry class and two dependent (child) classes; its object graph is depicted in Figure 6-1.

9781430250500_Fig06-01.jpg

Figure 6-1. OrderEntry object graph

When an OrderEntry object is created and initialized, its init method also creates instances of its two child classes; thus, the OrderEntry object claims an ownership interest in each of these objects. Later, when an OrderEntry object is deallocated, ARC automatically sends a release message to each of its child objects. Specifically, at compile time, ARC creates code that inserts a dealloc method for the OrderEntry object (if one doesn’t already exist), inserts a release message for each child object it owns, and then sends a dealloc message to the superclass of the OrderEntry object. Hence, ARC automatically manages the life cycle of object graphs.

The Apple Foundation Framework includes a variety of collection classes, so named because they are used to hold instances of other objects. When an object is stored in an instance of a collection class, the collection class claims an ownership interest in the object. Conversely, when a collection class instance is deallocated, ARC automatically sends a release message to each of the objects in the collection.

Creating Multiple Order Entries

To illustrate the use of ARC memory management and owner deallocation, you are going to extend the Order Entry project created in Chapter 4 by adding the capability to collect and store multiple order entries. You’ll use a collection class to store the entries, and then demonstrate how ARC performs memory management with collection classes and the objects stored therein.

In Xcode, open the ARC Orders project (if not already opened) by selecting Open Recent image ARC Orders.xcodeproj from the Xcode File menu. The source code for the project consists of seven files that implement the OrderEntry, OrderItem, and Address classes, and the main function. Let’s start by making some updates to the OrderItem class. Select the OrderItem.h file in the navigator pane and then update the OrderItem interface, as shown in Listing 6-4.

Listing 6-4.  ARC OrderItem Class Interface

#import <Foundation/Foundation.h>

@interface OrderItem : NSObject

@property (readonly) NSString *name;

- (id) initWithName:(NSString *)itemName;

@end

In Listing 6-4, the instance variable name has been changed to a read-only property. Next, select the OrderItem.m file and update the OrderItem implementation, as shown in Listing 6-5.

Listing 6-5.  ARC OrderItem Class Implementation

#import "OrderItem.h"

@implementation OrderItem

- (id) initWithName:(NSString *)itemName
{
  if ((self = [super init]))
  {
    _name = itemName;
    NSLog(@"Initializing OrderItem object %@", _name);
  }
  return self;
}

- (void)dealloc
{
  NSLog(@"Deallocating OrderItem object %@", self.name);
}

@end

This code is very similar to the original implementation; the custom initializer method (initWithName:) has been modified to initialize the property-backed instance variable. The log messages have also been slightly updated to display the OrderItem object name. Recall from Chapter 3, that for an autosynthesized property, the standard naming convention for its instance variable is the property name prefaced with an underscore. Now let’s update the OrderEntry class. Select the OrderEntry.h file in the navigator pane and then update the OrderEntry interface, as shown in Listing 6-6.

Listing 6-6.  ARC OrderEntry Class Interface

#import <Foundation/Foundation.h>
#import "OrderItem.h"
#import "Address.h"

@interface OrderEntry : NSObject

{
  Address *shippingAddress;
}

@property (readonly) NSString *orderId;
@property (readonly) OrderItem *item;

- (id) initWithId:(NSString *)oid name:(NSString *)order;

@end

The OrderEntry interface now has a single instance variable, two read-only properties, and an updated custom initializer (initWithId:name:). The properties are read-only and they replace two of the instance variables in the original interface from Chapter 4. Next, you’ll update the class implementation. Select the OrderEntry.m file in the navigator pane and update the implementation, as shown in Listing 6-7.

Listing 6-7.  ARC OrderEntry Class Implementation

#import "OrderEntry.h"

@implementation OrderEntry

- (id) initWithId:(NSString *)oid name:(NSString *)order;
{
  if ((self = [super init]))
  {
    NSLog(@"Initializing OrderEntry object");
    _orderId = oid;
    _item = [[OrderItem alloc] initWithName:order];
    shippingAddress = [[Address alloc] init];
  }
  
  return self;
}

- (void)dealloc
{
  NSLog(@"Deallocating OrderEntry object with ID %@",
        self.orderId);
}

@end

The custom initializer method (initWithId:name:) has been modified to initialize the two property-backed instance variables. The log message has also been slightly updated to display the OrderEntry ID using the property getter method.

Now that you’ve updated the classes, let’s update the main function to create some order entries and store them in a collection class. Select the main.m file in the navigator pane and then update the main function, as shown in Listing 6-8.

Listing 6-8.  ARC Orders main( ) Function Implementation

#import <Foundation/Foundation.h>
#import "OrderEntry.h"

int main(int argc, const char * argv[])
{

  @autoreleasepool
  {
    // Create an OrderEntry object
    OrderEntry *entry1 = [[OrderEntry alloc] initWithId:@"A-1"
                                                   name:@"2 Hot dogs"];
    NSLog(@"Order 1, ID = %@, item: %@", entry1.orderId, entry1.item.name);
    
    // Create another OrderEntry object
    OrderEntry *entry2 = [[OrderEntry alloc] initWithId:@"A-2"
                                                   name:@"1 Cheeseburger"];
    NSLog(@"Order 2, ID = %@, item: %@", entry2.orderId, entry2.item.name);

    // Add the order entries to a collection
    NSArray *entries = [[NSArray alloc] initWithObjects:entry1, entry2, nil];
    NSLog(@"Number of order entries = %li", [entries count]);
    
    // Set OrderEntry object to nil, ARC sends a release message to the object!
    NSLog(@"Setting entry2 variable to nil");
    entry2 = nil;
    
    // Set collection to nil, ARC sends a release message to all objects
    NSLog(@"Setting entries collection variable to nil");
    entries = nil;
    
    // Set OrderEntry object to nil, ARC sends a release message to the object!
    NSLog(@"Setting entry1 variable to nil");
    entry1 = nil;
    
    // Exit autoreleasepool block
    NSLog(@"Leaving autoreleasepool block");
  }
  return 0;
}

The updates to the main() function are extensive, so you’ll go over them line by line. First, the code creates two OrderEntry objects, each time logging a message to the console displaying the ID and name for the entry. Next, the code creates and initializes an NSArray object with the two order entries. An NSArray is a Foundation Framework class for managing order collections of objects (you’ll learn about NSArray and other Foundation Framework collection classes in Part 3 of this book). As you learned earlier, when an object is stored in an instance of a collection class, the collection class claims an ownership interest in the object. Thus, the NSArray object claims an ownership interest in each order entry. Next, the variable currently pointing to one of the OrderEntry objects (entry2) is set to nil, thereby releasing an ownership interest in the object. Because the NSArray object still “owns” the entry2 object, it is not deallocated. Next, the variable pointing to the NSArray object is set to nil, thereby releasing ownership interest in the entry2 object and in all objects for which it claims an ownership interest. Finally, the variable pointing to the other OrderEntry object (entry1) is set to nil, thereby releasing an ownership interest in that object. A message is also logged to the console immediately before leaving the autorelease pool block.

Now save, compile, and run the updated ARC Orders program and observe the messages in the output pane (see Figure 6-2).

9781430250500_Fig06-02.jpg

Figure 6-2. Testing the updated ARC Order Entry project

The messages in the output pane (depicted in more detail in Figure 6-3) show the sequence of calls to initialize and deallocate the dynamically created objects.

9781430250500_Fig06-03.jpg

Figure 6-3. ARC object deallocation

In Figure 6-3, a series of messages show the initialization of two OrderEntry object graphs, including their corresponding dependent objects (OrderItem and Address). A message indicating the number of order entries stored in the NSArray collection class is then displayed. Next, the entry2 variable (corresponding to an OrderEntry object) is set to nil; however, because the NSArray instance still has an ownership interest in this OrderEntry object, it is not deallocated. The entries variable (corresponding to the NSArray instance) is then set to nil. This causes the NSArray instance to be deallocated and a release message to be sent to each of the objects in this collection. At this point, the OrderEntry object corresponding to the entry2 variable has no more owners, so it is deallocated, along with its dependent objects. Next, the entry1 variable is set to nil, causing a release message to be sent to its corresponding OrderEntry object. Because this object now has no owners, it is also deallocated along with its dependent objects. The output pane now displays a message indicating that the code is leaving the autorelease pool block. Following this message, the corresponding OrderItem object for each of the OrderEntry objects is deallocated.

ARC memory management has properly managed the life cycle of this object graph and the collection class. However, if you look closely at the output from the output pane, you may have noticed that the OrderItem objects were deallocated at the end of the autorelease pool (as shown by the log messages in Figure 6-3). So why weren’t they deallocated when the corresponding OrderEntry parent objects were deallocated? The answer lies in how ARC manages the life cycle of property accessors—specifically in this case, property get methods. Your code needs to claim an ownership interest in any object it obtains (i.e., hasn’t created programmatically via a method beginning with alloc, new, copy, or mutableCopy) and may use over a long period of time. Because ARC prohibits you from programmatically sending retain messages to objects, it must be capable of detecting these scenarios and inserting the necessary code to manage object life cycle appropriately. Specifically, if an object is retrieved via a property get method, ARC detects this and automatically inserts code to send retain and autorelease messages to this object, thereby preventing it from being deallocated prematurely. Recall from Listing 6-6 that the OrderEntry interface declares a (read-only) property named item of type OrderItem. In Listing 6-8, the following statement retrieves the OrderItem object item via the property get method (entry1.item):

NSLog(@"Order 1, ID = %@, item: %@", entry1.orderId, entry1.item.name);

At compile time, ARC will automatically insert code that sends retain and autorelease messages to this OrderItem object. Later in the code, the OrderItem object (entry2.item) is retrieved with the following statement:

NSLog(@"Order 2, ID = %@, item: %@", entry2.orderId, entry2.item.name);

In sum, when an object is retrieved via a property getter, ARC sends retain and autorelease messages to the object to prevent it from being deallocated. This explains why the OrderItem objects were deallocated at the end of the autorelease pool block, and not when the parent (OrderEntry) objects were deallocated.

Let’s comment-out the preceding two log statements and then save, compile, and rerun the program. Because the OrderItem objects are no longer retrieved via a property get method, you should observe that the OrderItem objects are now deallocated when the corresponding OrderEntry objects are deallocated, not at the end of the autorelease pool block (see Figure 6-4).

9781430250500_Fig06-04.jpg

Figure 6-4. Running the updated ARC Order Entry project

This example demonstrates the details of how code compiled using ARC can programmatically release ownership interest in objects and how ARC manages object life cycle for both object graphs and collections. Understanding these details will become invaluable as you develop larger and more complex Objective-C applications.

Using ARC with Apple Frameworks and Services

Apple includes numerous software libraries (i.e., frameworks and services) that provide the interfaces needed to write software for the OS X and iOS platforms. Some of the most commonly used libraries for application development are depicted in Figure 6-5.

9781430250500_Fig06-05.jpg

Figure 6-5. Apple Application frameworks and services

The application programming interfaces (APIs) for some of these libraries are written in Objective-C, and thus may be used directly in your Objective-C programs. The APIs for the majority of these libraries are written in ANSI C, and hence may also be used directly in your Objective-C programs.

You may recall from Chapter 4 that ARC provides automatic memory management for Objective-C objects and block objects. The Apple software libraries with C-based APIs do not integrate with ARC. Thus, you are responsible for programmatically performing memory management when dynamically allocating memory with these C-based APIs. In fact, when using ARC, it is prohibited to perform standard casts between pointers of Objective-C objects and pointers of other types (e.g., one that is a part of an Apple C–based API). Apple provides several mechanisms (toll-free bridging and ARC bridged casts) to facilitate the use of C-based APIs in Objective-C programs. You will look at these next.

Objective-C Toll Free Bridging

Interoperability is provided for a number of data types in the C-based Core Foundation Framework and the Objective-C-based Foundation Framework. This capability, referred to as toll-free bridging, allows you to use the same data type as the parameter to a Core Foundation function call or as the receiver of an Objective-C message. You can cast one type to the other to suppress compiler warnings. Some of the more commonly used toll-free bridged data types are listed in Table 6-1; it includes the Core Foundation type and the corresponding Foundation Framework type.

Table 6-1. Toll-Free Bridging Data Types

Core Foundation Type Foundation Type
CFArrayRef NSArray
CFDataRef NSData
CFDateRef NSDate
CFDictionaryRef NSDictionary
CFMutableArrayRef NSMutableArray
CFMutableDataRef NSMutableData
CFMutableDictionaryRef NSMutableDictionary
CFMutableSetRef NSMutableSet
CFMutableStringRef NSMutableString
CFNumberRef NSNumber
CFReadStreamRef NSInputStream
CFSetRef NSSet
CFStringRef NSString
CFWriteStreamRef NSOutputStream

With toll-free bridging, the compiler implicitly casts between Core Foundation and Foundation types. For example, a variable of type CFStringRef is used as an argument to an Objective-C method in Listing 6-9.

Listing 6-9.  Toll-Free Bridging Implicit Cast

CFStringRef cstr = CFStringCreateWithCString(NULL, "Hello, World!",
                                                 kCFStringEncodingASCII);
NSArray *data = [NSArray arrayWithObject:cstr];

The [NSArray arrayWithObject:] class method takes a parameter of type id (in other words, an Objective-C object pointer) as an argument, but is passed as CFStringRef. Because CFStringRef is a toll-free bridged data type, the cstr parameter is implicitly cast to an NSString object (see Table 6-1). To remove the compiler warning for the implicit cast, the parameter is cast, as shown in Listing 6-10.

Listing 6-10.  Toll-Free Bridging Explicit Cast

CFStringRef cstr = CFStringCreateWithCString(NULL, "Hello, World!",
                                                 kCFStringEncodingASCII);
NSArray *data = [NSArray arrayWithObject:(NSString *)cstr];

As mentioned in the previous section, the Objective-C compiler does not automatically manage the lifetimes of Core Foundation data types. Therefore, to use Core Foundation toll-free bridged types in ARC memory managed Objective-C programs, it is necessary to indicate the ownership semantics involved with these types. In fact, the code in Listing 6-10, as is, will not compile when using ARC! For Objective-C programs that use ARC memory management, you must indicate whether the life cycle of a toll-free bridged type is to be managed by ARC or managed programmatically. You do this by using ARC bridged casts.

ARC Bridged Casts

ARC bridged casts enable the use of toll-free bridged types when using ARC. These casting operations are prefaced with the special annotations __bridge , __bridge_retained , and __ bridge_transfer.

  • The __bridge annotation casts an object from a Core Foundation data type to a Foundation object (or vice-versa) without transfer of ownership. In other words, if you dynamically create a Foundation Framework object, and then cast it to a Core Foundation type (via toll-free bridging), the __bridge annotation informs the compiler that the object’s life cycle is still managed by ARC. Conversely, if you create a Core Foundation data type and then cast it to a Foundation Framework object, the __bridge annotation informs the compiler that the object’s life cycle must still be managed programmatically (and is not managed by ARC). Note that this annotation removes the compiler error but doesn’t transfer ownership; thus, care is required when using it to avoid memory leaks or dangling pointers.
  • The __bridge_retained annotation is used to cast a Foundation Framework object to a Core Foundation data type and transfer ownership from the ARC system. You are then responsible for programmatically managing the lifetime of the bridged data type.
  • The __bridge_transfer annotation is used to cast a Core Foundation data type to a Foundation object and also transfer ownership of the object to the ARC system. ARC will then programmatically manage the lifetime of the bridged object.

The syntax for using a bridged cast annotation in a cast operation is

(annotation castType)variableName

This differs from a regular cast operation in that the annotation is prepended to the cast type. The ARC bridged casts can be used not only for toll-free bridged types, but also anywhere your Objective-C code needs to use access memory not managed as Objective-C objects. Listing 6-11 updates the previous example with an ARC bridged cast.

Listing 6-11.  Toll-Free Bridging with an ARC Bridged Cast

CFStringRef cstr = CFStringCreateWithCString(NULL, "Hello, World!",
                                                 kCFStringEncodingASCII);
NSArray *data = [NSArray arrayWithObject:(__bridge_transfer NSString *)cstr];

Notice that the annotation precedes the type being cast to. This annotation transfers ownership of the bridged object to ARC, which will now manage the object’s life cycle. OK, enough theory, now let’s create some examples that demonstrate the use of ARC bridged casts!

Using ARC Bridged Casts

Now you’ll develop an example program that applies what you’ve learned about toll-free bridging and ARC bridged casts. In Xcode, create a new project by selecting New image Project ... from the Xcode File menu. In the New Project Assistant pane, create a command-line application (choose Command Line Tool from the Mac OS X Application selection) and click Next. In the Project Options window, specify ARC Toll Free Bridging for the Product Name, choose Foundation for the Project Type, choose ARC memory management by selecting the Use Automatic Reference Counting check box, and then click Next.

Specify the location in your file system where you want the project to be created (if necessary, select New Folder and enter the name and location for the folder), uncheck the Source Control check box, and then click the Create button.

First, you’ll create a toll-free bridged Core Foundation data type. Select the main.m file in the navigator pane and create a CFStringRef, as shown in Listing 6-12.

Listing 6-12.  A main( ) Function Toll-Free Bridged Data Type

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
  @autoreleasepool
  {
    CFStringRef cstr = CFStringCreateWithCString(NULL, "Hello, World!",
                                                 kCFStringEncodingASCII);
  }
  return 0;
}

A CFStringRef is a Core Foundation data type that represents a unicode string of characters. It is a toll-free bridged type and it can be cast to a Foundation Framework NSString object. To demonstrate the use of toll-free bridging, update the code, as shown in Listing 6-13.

Listing 6-13.  Implicit Toll-Free Bridging

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
  @autoreleasepool
  {
    CFStringRef cstr = CFStringCreateWithCString(NULL, "Hello, World!",
                                                 kCFStringEncodingASCII);
    NSArray *data = [NSArray arrayWithObject:cstr];
    NSLog(@"Array size = %ld", [data count]);
    ...
}

The variable cstr, of type CFStringRef, is a parameter for the Objective-C NSArray object. From a toll-free bridging perspective, this is all fine, but because you are using ARC memory, the code will not compile. It displays an error indicating that a bridged cast is required (see Figure 6-6).

9781430250500_Fig06-06.jpg

Figure 6-6. Toll-Free bridging compilation error

The Xcode pop-up message recommends that you update the code with a bridged cast using the __bridge annotation. If you make this update, the code now compiles and runs. There is a potential problem, however. Can you guess what it is? Well, if you analyze this program (by selecting Analyze from the Xcode Product menu), there is a potential memory leak of the object stored in the cstr variable (see Figure 6-7).

9781430250500_Fig06-07.jpg

Figure 6-7. Bridged cast potential memory leak

This problem occurs because the __bridge annotation doesn’t transfer ownership of the toll-free bridged object; thus, your code must programmatically manage the life cycle of the object pointed to by cstr. Because your code created the CFStringRef, it owns this dynamically created object and can send a release message to it, as in the following, for example:

CFRelease(cstr);

This will eliminate the potential memory leak. A better solution (which will avoid having to programmatically manage the life cycle of this object), however, is to use the __bridge_transfer annotation. This will transfer ownership of the object to ARC, which will then automatically manage the object’s life cycle.

NSArray *data = [NSArray arrayWithObject:(__bridge_transfer NSString *)cstr];

If you analyze the program again after making this change, no memory leaks are detected. Cool. Now let’s create another example. This one casts a Foundation Framework object to a Core Foundation data type. Add the code shown in Listing 6-14.

Listing 6-14.  Implicit Toll-Free Bridging

// Now cast a Foundation framework object to a Core Foundation type
NSString *greeting = [[NSString alloc] initWithFormat:@"%@",
                      @"Hello, World!"];
CFStringRef cstr1 = (__bridge CFStringRef)(greeting);
printf("String length = %ld", CFStringGetLength(cstr1));

This code creates a Foundation Framework NSString instance and uses the __bridge annotation to cast it to a Core Foundation CFStringRef. This code compiles and runs, but has a potential dangling pointer because ARC immediately sends a release message to the NSString object (stored in the variable greeting) when the bridged cast is performed. To resolve this problem, change the cast annotation to __bridge_retained. This transfers ownership of the object from ARC, thereby preventing ARC from sending the release message to the object. You must now programmatically manage the life cycle of the object (now cast to a CFStringRef). Add a CFRelease function call after the printf statement.

CFRelease(cstr1);

If you analyze the program now, there are no potential memory leaks detected. When you compile and run the program, you’ll see the output shown in Figure 6-8.

9781430250500_Fig06-08.jpg

Figure 6-8. Bridged casts to Core Foundation types and Foundation Framework objects

Great! You now have a good handle on toll-free bridging and the use of ARC bridged casts. Feel free to experiment with other toll-free bridged types to get familiar with this technology under ARC.

Roundup

This Expert Section chapter explored some of the finer details surrounding ARC memory management. Because ARC is the Apple-recommended approach for memory management on all new Objective-C projects, it is critical to have a good understanding of how to use this technology. In this chapter, you focused on the details of ARC object ownership, block objects, and toll-free bridging. To recap, the following are the key takeaways:

  • ARC prohibits programmatic use of the release, autorelease, dealloc, or related messages on an object. Your code gives up ownership interest in an object when it performs any of the following: 1) variable reassignment, 2) nil assignment, or 3) its owner is deallocated.
  • Variable reassignment occurs when a variable that points to a dynamically created object is changed to point to another object. At this point, the object loses an owner; at compile time, ARC inserts code to send a release message to this object.
  • nil assignment occurs when the value of a variable that currently points to a dynamically created object is set to nil. At this point, the object loses an owner. At compile time, ARC inserts code to send a release message to this object.
  • Owner deallocation occurs for collection class instances. When a collection class instance is deallocated, ARC automatically sends a release message to each of the objects in the collection.
  • Apple includes numerous software libraries (i.e., frameworks and services) that provide the interfaces needed to write software for the OS X and iOS platforms. The APIs for the majority of these libraries are written in ANSI C, and thus these libraries can be used in your Objective-C programs. The Apple software libraries with C-based APIs do not integrate with ARC; so your code is responsible for programmatically performing memory management when dynamically allocating memory with these C-based APIs.
  • When using ARC, it is prohibited to perform standard casts between pointers of Objective-C objects and pointers of other types (e.g., one that is a part of an Apple C-based API). Apple provides several mechanisms (toll-free bridging and ARC bridged casts) to facilitate the use of C-based APIs in Objective-C programs.
  • Toll-free bridging, provided for a number of data types in the Core Foundation and Foundation Frameworks, enables your code to use the same data type as the parameter to a Core Foundation function call or as the receiver of an Objective-C message. You can cast one type to the other to suppress compiler warnings. Under ARC memory management, you cannot directly cast toll-free bridged types; they must be prepended with special ARC bridged cast annotations.
  • ARC bridged casts enable the use of toll-free bridged types when using ARC. These casting operations are prefaced with the special annotations __bridge , __bridge_retained , and __bridge_transfer.

Well, Part 1 has been quite a journey! You have learned many of the fundamentals of the Objective-C language. Take your time to review everything that you have learned in these six chapters, because having a sound foundation with this material is critical to becoming proficient in programming with Objective-C. Next up is Part Two, where you explore the Objective-C Runtime. When you’re ready, turn the page and let’s begin!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.127.37