- The Stack
- The Heap
- Pointer Variables and Object Ownership
- Strong and Weak References
- Properties
- For the More Curious: Property Synthesis
- For the More Curious: Autorelease Pool and ARC History
Pointer Variables and Object Ownership
Pointer variables imply ownership of the objects that they point to.
- When a method (or function) has a local variable that points to an object, that variable is said to own the object being pointed to.
- When an object has an instance variable that points to another object, the object with the pointer is said to own the object being pointed to.
Think back to your RandomItems application. In this application, an instance of NSMutableArray is created in main() and then ten BNRItem instances are added to it. Figure 3.2 shows some of the objects in RandomItems and the pointers that reference them.
Figure 3.2 RandomItems object diagram (with only two items)
Within main(), the local variable items points to an instance of NSMutableArray, so main() owns that NSMutableArray instance.
The array, in turn, owns the BNRItem instances. A collection object, like an instance of NSMutableArray, holds pointers to objects instead of actually containing them, and these pointers imply ownership: an array always owns the objects that are “in” the array.
Finally, each BNRItem instance owns the objects pointed to by its instance variables.
The idea of object ownership is useful for determining whether an object will be destroyed so that its memory can be reused.
- An object with no owners will be destroyed. An ownerless object cannot be sent messages and is isolated and useless to the application. Keeping it around wastes precious memory. This is called a memory leak.
- An object with one or more owners will not be destroyed. If an object is destroyed but another object or method still has a pointer to it (or, more accurately, a pointer that stores the address where the object used to live), then you have a dangerous situation: sending a message via this pointer may crash your application. Destroying an object that is still needed is called premature deallocation. It is also known as a dangling pointer or a dangling reference.
How objects lose owners
Here are the ways that an object can lose an owner:
- A variable that points to the object is changed to point to another object.
- A variable that points to the object is set to nil.
- The owner of the object is itself destroyed.
- An object in a collection, like an array, is removed from that collection.
Let's take a look at each of these situations.
Changing a pointer
Imagine an instance of BNRItem. Its _itemName instance variable points to an NSString instance @"RustySpork". If you polished the rust off that spork, it would become a shiny spork, and you would want to change the_itemName to point at a different NSString.
When the value of _itemName changes from the address of the “Rusty Spork” string to the address of the “Shiny Spork” string, the “Rusty Spork” string loses an owner. If it has no other owners, then it will be destroyed.
Setting a pointer to nil
Setting a pointer to nil represents the absence of an object. For example, say you have a BNRItem instance that represents a television. Then, someone scratches off the television's serial number. You would set its _serialNumber instance variable to nil. The NSString instance that _serialNumberpreviously pointed to loses an owner.
The owner is destroyed
When an object is destroyed, the objects that it owns lose an owner. In this way, one object being deallocated can cause a cascade of object deallocations.
Through its local variables, a method or a function can own objects. When the method or function is done executing and its frame is popped off the stack, the objects it owns will lose an owner.
Removing an object from a collection
There is one more important way an object can lose an owner. An object in a collection object is owned by the collection object. When you remove an object from a mutable collection object, like an instance of NSMutableArray, the removed object loses an owner.
[items removeObject:item]; // Object pointed to by item loses an owner
Keep in mind that losing an owner by any of these means does not necessarily result in the object being destroyed; if there is still another pointer to the object somewhere, then the object will continue to exist. When an object loses its last owner, the result is certain and appropriate death.
Ownership chains
Because objects own 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.
There is an example of this in RandomItems. Take another look at the object diagram for this application.
Figure 3.3 Objects and pointers in RandomItems
In main.m, after you finish printing out the array, you set the items variable to nil. Setting items to nil causes the array to lose its only owner, so the array is destroyed.
But the destruction does not stop there. When the array is destroyed, all of the pointers to the BNRItem instances are destroyed. Once these variables are gone, no one owns any of the items, so they are destroyed.
Finally, destroying a BNRItem destroys its instance variables, which leaves the objects pointed to by those variables unowned. So they, too, get destroyed.
Let's add some code so that you can see this destruction as it happens.NSObject implements a dealloc method, which is sent to an object just before it is destroyed. You can override dealloc in BNRItem to print something to the console when an item is destroyed.
In the RandomItems project, 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 items 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 as the result of setting items to nil. That is the power of ARC.