Hour 16. Managing Memory and Runtime Objects


What You’ll Learn in This Hour

Image Reviewing memory management for objects

Image Using manual reference counting

Image Using Automatic Reference Counting


Managing Objects in Memory

One of the most significant ways in which object-oriented programs and their languages differ from traditional programming is in their use of memory. In older styles of programming, variables were declared in blocks and could be used throughout the block in which they were declared. (Sometimes the entire program was one block.) Variables were placed on the stack when control entered into a block, and when control left the block, the stack was cut back so that the variables were no longer accessible, and their memory was restored to the operating system.

With objects, there is a different pattern of use. It is not the mere declaration of a variable in a block that allocates memory; rather, it is the creation of the object that takes up memory. At the end of the object’s life cycle, the deletion of the object releases its memory.

It is no longer a question of the scope of variables that determines their existence and memory usage but rather the programmer’s creation and destruction of the object. It is true that there are some cases in which an object is created and destroyed in a single block, but often an object is created in one place in a program and destroyed in another.

Objective-C and the Cocoa frameworks have addressed the issue of managing memory for objects in two ways:

Image Reference counting—Objects carry with them a reference count that represents the number of parties interested in the object. As long as the reference count is greater than zero, the object is deemed to be in use and cannot be deleted. When an interested party is no longer interested in the object, the reference count is decremented by one. When it reaches zero, that signifies that there is no interest in the object and it can be safely deleted.

Image Garbage collection—At runtime, the interested parties are tracked without the use of reference counters. Periodically, a garbage collection process deletes objects that are no longer needed. Although the code can be highly optimized, it nevertheless adds to the burden on the computer’s resources.


Note

Garbage collection has never been implemented on iOS, and it is now deprecated on OS X. However, you still find references to it in various documents and in old code.


The biggest distinction between these two methods is when they are performed. Reference counting is coded by the developer as the app is being written. Garbage collection happens at runtime, but the developer does not have to worry about managing reference counts.

This is no small consideration because implementing the reference counting code is not particularly complex in the way that managing a multidimensional array can be, but it is remarkably unforgiving. One reference count decrement in the wrong place can let the OS know that it is safe to delete an object when it is not. On the other hand, one reference count increment too many can prevent an object from ever being deleted, and you and your users will have to contend with memory leaks.

With the advent of Mac OS X 10.7 (Lion) and iOS 5, Automatic Reference Counting (ARC) entered the picture. (ARC is pronounced just as the arc of a circle is pronounced.) ARC imposes no runtime burden on the app because it is implemented in the compiler and optimizer. It relies on Cocoa naming conventions to actually generate the code that you had to hand-code in the past to manage reference counting.

Today, reference counting is the basis of memory management for Objective-C. In older apps, it is implemented explicitly using methods of NSObject and the NSObject protocol. In modern code, it is implemented with ARC. Accordingly, this hour focuses on reference counting techniques.

Managing Reference Counts Manually

ARC implements reference counting in the compiler and optimizer, but you still should understand what it is doing for you. If you are working on older code, you definitely need to understand manual reference counting because that is what you see in your code. Even with new code, not every developer is able to switch over to using ARC, so that is yet another reason for understanding the process.

Because ARC is implementing reference counting behind the scenes, in the unlikely event that something goes wrong, understanding reference counting may help you troubleshoot the problems. However, if you are working only on new code, you can postpone learning about reference counting and just focus on ARC (as described in the following section).

Looking at Memory Management Before ARC

In Hour 14, “Defining a Class in an Implementation File,” you saw how to build a small converter. In Hour 14, you built it with ARC. If you were writing this code in the past (that is, before iOS 5 or Lion), you probably would have written it differently. In the listings that follow, you see comments on the lines that would have been written differently in older versions of the operating systems.

Xcode has turned on ARC starting in the Apple LLVM Compiler 3.0. The settings are in Apple LLVM 5.0 – Language – Objective-C under Build Settings for your project once you have selected your project in the project navigator—and, if necessary, scrolled down to that section. You can also manually adjust the various ARC warnings, as shown in Figure 16.1. There are additional options in Apple LLVM 5.0 – Warnings – Objective C and ARC.

Image

FIGURE 16.1 Adjust ARC warnings.

Listing 16.1 shows the interface file as it would have been written before ARC. (Compare this to Figure 14.3 in Chapter 14.) Remember, you should not be writing new code this way. It is presented here because there is still so much pre-ARC code around that you might have to understand, debug, and even modify it.

LISTING 16.1 AppDelegate.h


#import <UIKit/UIKit.h>

@class Converter;

@interface AppDelegate : NSObject <UIApplicationDelegate>

  @property (assign) IBOutlet NSWindow *window; //pre-ARC
  @property (retain) Converter *currencyConverter; //pre-ARC
@end


The setter attributes of the property declarations in the pre-ARC world can now be described. The property for the IBOutlet window is set to assign. This means that a simple assignment statement is used to set the property. The object itself is created at runtime based on your settings in Interface Builder, so it is not an object that your code creates.

When currencyConverter is set, a retain message is sent to the object as it is assigned. As described previously, each retain message must be balanced with a release message so that the reference count is properly adjusted. The property declaration as shown here provides the retain.

Summarizing Memory Management

There is a great deal of material on developer.apple.com covering memory management. In particular, you will find examples and discussion of retain cycles. The most common case of a retain cycle is that in which two objects each retain the other.

“Advanced Memory Management Programming Guide” on developer.apple.com provides a thorough guide to what happens. It summarizes what you need to know in three points:

Image “You own any object you create [...] using a method whose name starts with alloc, new, copy, or mutableCopy.” You do not need to retain these objects because you already own them.

Image “You can take ownership of an object using retain.” The object will not be deleted as long as you continue to own it, and that leads to the final point...

Image “You must release any object when you no longer need it. If you do not, it will not be deallocated and its memory will continue to be held in use. Note that you release an object when you no longer need it. Releasing it in no way suggests that no one else needs it—other parties release it when they are done with it.”

Managing memory in this way is not very complicated conceptually. However, as you will see from the volume of information and discussion on developer.apple.com, this form of memory management is labor and detail intensive. Automatic Reference Counting addresses those issues.

Managing Reference Counts with ARC

When ARC is turned on, the compiler and optimizer implement the needed retain, release, and dealloc code. In fact, you are not allowed to use them. For pre-ARC projects, you can turn ARC on; however, that can break existing code.

You might not notice it at first, but as soon as you clean a project where you have turned on ARC and built it again, you have errors. For this reason, you are safer using the Edit, Refactor, Convert to Objective-C ARC command for legacy projects. You will have a chance to compare the before and after versions of changed files, and Xcode will normally take care of problems.


Tip

Note, however, that there are a few circumstances in which Xcode cannot do the ARC conversion. At least in this author’s experience, Xcode handles most conversions well; and if it can’t do the conversion, it advises you. There are few if any reports of faulty conversions to ARC.


Using Cocoa Coding Conventions to Take Advantage of ARC

ARC relies on the Cocoa coding conventions—particularly the convention that a method name begins with a verb. The following verbs cause ARC to retain the object that is returned: alloc, init, new, and copy. Thus, a method called prepareMyObjectAndCopy does not trigger an ARC retain (and it also is a bad method name for other reasons).

Using Declared Property Attributes

There is another issue for you to confront when you are using ARC and iOS 5 or later along with Mac OS X 10.7 (Lion) or later. There are some modifications to declared property attributes. Property attributes before these versions included the following types and values:

Image Accessor method names—You can specify methods to use for getter and setter if you want to write your own accessors. If you do not use your own accessors, they are created for you with the default names.

Image Writeability—The values are readwrite and readonly.

Image Setter semantics—These determine what happens when the property is set. Until iOS 5 and Mac OS X 10.7, the only values were assign, retain, and copy. There are additional values that are described in the following section.

Image Atomicity—If your accessors are nonatomic, you can use the nonatomic keyword. (There is not a comparable atomic setting; it is the default.)

The setter semantic values make sense in the world of ARC, and they remain available to you. This avoids breaking existing code, but it means that you have to think about the memory management and reference counting that the compiler now implements for you. Two new keywords listed below are available to let you avoid thinking about the details of reference counting:

Image strong—A synonym for retain. It describes the link to the object rather than the action to take when setting the property. Do not worry: It is a true synonym and a retain message is going to be generated, but when you think about strong, you are thinking about the link to the object and letting the compiler handle the mechanics of implementing it.

Image weak—Similar to assign, but it also focuses on the nature of the link to the object rather than on the mechanics of implementation. It is not exactly the same as assign because it implements a significant additional feature.


Note

In pre-ARC days, it was very common to wind up with dangling pointers to objects. If you have a property that points to an object, and if that object is deallocated, the property still points to where the object was.

The best practice was to set the property to nil immediately after releasing it so that the pointer was safe. Remember that sending a message to a nil object is not an error.


With the weak keyword, if the object that the property points to is deallocated, the property is automatically set to nil. This saves a great deal of time that previously was spent debugging crashes. It also might prevent some memory leaks that were caused by people being hesitant to release objects. This was never a good programming practice, but it was definitely used in many cases.


Caution

An additional keyword, unsafe_unretained, implements exactly the old assign functionality. However, its use is discouraged because you might wind up with a dangling pointer.


strong and weak are not required for ARC; you can continue using assign and retain. However, over time, assign and retain will probably wind up requiring more explanation than strong and weak as the details of manual reference counting for memory management slip into the past. Using strong and weak makes the code more readable.

Variable Qualifiers

If you are using variables directly (as opposed to properties), you can attach qualifiers to them. In most cases, you do not need to use them because the default (__strong) is correct in most cases. These are the variable qualifiers available with ARC. Note that each one starts with two underscore characters.

Image __strong—This is the default value for variables, so you do not need to specify it.

Image __weak—This is used for a reference to an object that may disappear—exactly as is the case with the setter semantic for declared properties. If the object disappears, the variable is set to nil.

Image __unsafe_unretained—This self-explanatory qualifier is used to reference objects that might not be zeroed out with nil when the object disappears.

Image __autoreleasing—This is a part of a new implementation of autoreleasing that is described in the next section.

Autoreleasing Variables

The retain message is processed immediately when it is sent. Until you send a release message, you own the object you have retained, and you can rely on it being present.


Tip

Your ownership might not be unique because there may be other owners. Each one is guaranteed that the object will be there until the owner releases it. It might be there longer if other owners still own it, but once you have released your ownership, you don’t care.


As you saw in Listing 16.1, it is common to release a number of objects at the same time when you are finished with them. In many cases, your retain messages are scattered through your code as you encounter the need for them, but you may release them at a known location (such as a dealloc method). The NSAutoreleasePool class lets you add to-be-released objects to a pool from which they are all released at the same time. This is particularly useful in tight loops where the objects are being retained and released in rapid succession.

Before ARC, this was implemented with a class. Your code would look like this:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init;
  // code in which you retain objects
  [pool release];

Once you have a pool, you add objects to it as you create them. NSObject protocol has an autorelease method that adds that object to the current autorelease pool. It’s typically used in this way:

[[[SomeObject alloc] init] autorelease]

You no longer have to deal with autorelease pools directly. You use a compiler directive that is similar to a try block to delimit the pool. The syntax is quite simple: Use the @autoreleasepool directive and place the code for the objects to be autoreleased in brackets. Here is how the previous code is now written:

@autoreleasepool {
  // code in which you retain objects
}

A frequent use of an @autoreleasepool block is to delimit code in which a large number of objects are created. On exit from the block, they are released. ARC would get around to doing so, but this can speed up the process and reduce the memory footprint.

Summary

Before ARC, you had to manually take care of memory management for the objects you created. In this chapter, you find a brief overiew of how memory management is implemented with reference counting as well as a discussion of how ARC automates that process for you.

Q&A

Q. What are the most common problems that result from manual reference counting?

A. Memory leaks and app crashes are the most common problems that result from manual reference counting. Be thankful for ARC!

Q. Why should you think twice about converting existing code to ARC?

A. Because constructs such as retain, release, and dealloc are not allowed under ARC, you may break existing code.

Workshop

Quiz

1. Why are the Cocoa coding conventions so important with ARC?

2. What is the difference between garbage collection and reference counting?

Quiz Answers

1. The initial verb in a method name (alloc, init, new, or copy) triggers ARC to retain an object.

2. Garbage collection is a process that runs at runtime. Reference counting is implemented when the code is written and compiled. Its effects are seen at runtime.

Activities

Adding ARC to an existing Xcode project can break it, as pointed out in this hour. However, it is worth your time to experiment with an old project to see how much damage is done. There are projects that have little damage by adopting ARC. These can be projects that you (or someone else) might have written when you were first starting out. If a project totally ignores memory management, it might leak like a sieve, but for some small projects that doesn’t matter. In a case such as that, moving to ARC plugs the leaks with minimal effort on your part. Just remember: When you switch the ARC settings, clean your project before rebuilding it. And, of course, work in a copy of the code.

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

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