destroyed; if there is still another pointer to the object somewhere, then that object will continue to exist. However, when an object loses its last owner, it means certain and appropriate death.
Because objects own other objects, which can own other objects, the destruction of a single object can set off a chain reaction of loss of ownership, object destruction, and freeing up of memory.
We have an example of this in RandomPossessions . Take another look at the object diagram of this application.
Figure 3.6 Objects and pointers in RandomPossessions
In main.m , after you finish printing out the array of BNRItem s, you set the items variable to nil . Setting items to nil causes the array to lose its only owner, so that array is destroyed.
But it doesn’t stop there. When the NSMutableArray is destroyed, all of its pointers to BNRItem s are destroyed. Once these variables are gone, no one owns any of the BNRItem s, so they are all destroyed. Destroying a BNRItem destroys its instance variables, which leaves the objects pointed to by those variables unowned. So they get destroyed, too.
Let’s add some code so that we can see this destruction as it happens. NSObject implements a dealloc method, which is sent to an object when it is about to be destroyed. We can override this method in BNRItem to print something to the console when a BNRItem is destroyed. In RandomPossessions.xcodeproj , open BNRItem.m and override dealloc .
- (void)dealloc
{
NSLog(@"Destroyed: %@", self);
}
In main.m , add the following line of code.
NSLog(@"Setting items to nil...");
items = nil;
Build and run the application. After the BNRItem s print out, you will see the message announcing that items is being set to nil . Then, you will see the destruction of each BNRItem logged to the console.
At the end, there are no more objects taking up memory, and only the main function remains. All this automatic clean-up and memory recycling occurs simply by setting items to nil . That’s the power of ARC.
Strong and Weak References
So far, we’ve said that anytime a pointer variable stores the address of an object, that object has an owner and will stay alive. This is known as a strong reference . However, a variable can optionally not take ownership of an object it points to. A variable that does not take ownership of an object is known as a weak reference .
A weak reference is useful for an unusual situation called a retain cycle . A retain cycle occurs when two or more objects have strong references to each other. This is bad news. When two objects own each other, they will never be destroyed by ARC. Even if every other object in the application releases ownership of these objects, these objects (and any objects that they own) will continue to exist by virtue of those two strong references.
Thus, a retain cycle is a memory leak that ARC needs your help to fix. You fix it by making one of the references weak. Let’s introduce a retain cycle in RandomPossessions to see how this works. First, we’ll give BNRItem instances the ability to hold another BNRItem (so we can represent things like backpacks and purses). In addition, a BNRItem will know which BNRItem holds it. In BNRItem.h , add two instance variables and accessors
@interface BNRItem : NSObject
{
NSString *itemName;
NSString *serialNumber;
int valueInDollars;
NSDate *dateCreated;
BNRItem *containedItem;
BNRItem *container;
}
+ (id)randomItem;
- (id)initWithItemName:(NSString *)name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber;
- (void)setContainedItem:(BNRItem *)i;
- (BNRItem *)containedItem;
- (void)setContainer:(BNRItem *)i;
- (BNRItem *)container;
Implement the accessors in BNRItem.m .
- (void)setContainedItem:(BNRItem *)i
{
containedItem = i;
// When given an item to contain, the contained
Mary Ellis
John Gould
Danielle Ellison
Kellee Slater
Mercedes Lackey
Lindsay Buroker
Isabel Allende
Kate Williams
Ardy Sixkiller Clarke
Alison Weir