- The Heap
- The Stack
- Pointer Variables and Object Ownership
- Memory Management
- Strong and Weak References
- Properties
- Copying
- Dot Syntax
- For the More Curious: Autorelease Pool and ARC History
For the More Curious: Autorelease Pool and ARC History
Before automatic reference counting (ARC) was added to Objective-C, we had manual reference counting. With manual reference counting, ownership changes only happened when you sent an explicit message to an object.
[anObject release]; // anObject loses an owner [anObject retain]; // anObject gains an owner
This was a bummer: Forgetting to send release to an object before setting a pointer to point at something else was a guaranteed memory leak. Sending release to an object if you had not previously sent retain to the object was a premature deallocation. A lot of time was spent debugging these problems, which could become very complex in large projects.
During the dark days of manual reference counting, Apple was contributing to an open source project known as the Clang static analyzer and integrating it into Xcode
.
You’ll see more about the static analyzer in Chapter 21, but the basic gist is that it could analyze code and tell you if you were doing something silly. Two of the silly things
it could detect were memory leaks and premature deallocations. Smart programmers would run their code through the static analyzer to detect these problems and then write
the necessary code to fix them.
Eventually, the static analyzer got so good that Apple thought, “Why not just let the static analyzer insert all of the retain and release messages?” Thus, ARC was born. People rejoiced in the streets, and memory management problems became a thing of the past.
(Some people have an irrational fear of letting the compiler do their work for them and say they prefer manual memory management for this reason. If someone says something like that to you, open up one of their .m files, go to the Product
menu, and select Generate Assembly File
from the
Generate Output
menu item. Tell them if they don’t trust the compiler, then they should be writing the assembly code they see in front of them. )
Another thing programmers had to understand in the days of manual reference counting was the autorelease pool. When an object was sent the message autorelease, the autorelease pool would take ownership of an object temporarily so that it could be returned from the method that created it without burdening the creator or the receiver with ownership responsibilities. This was crucial for convenience methods that created a new instance of some object and returned it:
- (BNRItem *)someItem { BNRItem *item = [[[BNRItem alloc] init] autorelease]; return item; }
Because you had to send the release message to an object to relinquish ownership, the caller of this method had to understand its its ownership responsibilities. But it was easy to get confused.
BNRItem *item = [BNRItem someItem]; // I guess I own this now? NSString *string = [item itemName]; // Well if I own that, do I own this?
Thus, objects created by methods other than alloc and copy would be sent autorelease before being returned, and the receiver of the object would take ownership as needed or just let it be destroyed after using it within the method in which it was returned.
With ARC, this is done automatically (and sometimes optimized out completely). An autorelease pool is created by the @autoreleasepool directive followed by curly brackets. Inside those curly brackets, any newly instantiated object returned from a method that doesn’t have alloc or copy in its name is placed in that autorelease pool. When the curly bracket closes, any object in the pool loses an owner.
@autoreleasepool { // Get a BNRItem back from a method that created it, method doesn't say alloc/copy BNRItem *item = [BNRItem someItem]; } // item loses an owner and is destroyed because nothing else took ownership of it
iOS applications automatically create an autorelease pool for you, and you really don’t have to concern yourself with it. But isn’t it nice to know what that @autoreleasepool is for?