Cocoa Programming for Mac OS X - Aaron Hillegass [30]
The final idiom is “Autorelease Old Value”:
- (void)setFoo:(NSDate *)x
{
[foo autorelease];
foo = [x retain];
}
Here, you autorelease the old value. Trade-off: An error in retain counts will result in a crash one event loop after the error. This behavior makes the bug harder to track down. In the first two idioms, your crash will happen closer to your error. Also, autorelease carries some performance overhead.
You have read the trade-offs and can make your own decision on which to use. In this book, we will use “Retain, Then Release.”
The “getter” method for an object is the same as that for a nonpointer type:
- (NSDate *)foo
{
return foo;
}
Most Java programmers would name this method getFoo. Don’t. Objective-C programmers call this method foo. In the common idioms of Objective-C, a method prefixed with get takes an address where data can be copied. For example, if you have an NSColor object and you want its red, green, blue, and alpha components, you would call getRed:green:blue:alpha: as follows:
float r, g, b, a;
[myFavoriteColor getRed:&r green:&g blue:&b alpha:&a];
(For readers who might be a bit rusty with their C, & returns the address where the variable holds its data.)
If you used your accessor methods to read the variables, your description method would look like this:
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ = %d and %d",
[self entryDate], [self firstNumber], [self secondNumber]];
}
OO purists would argue that this is the most correct implementation of the description method.
Change setEntryDate: in LotteryEntry.m to correctly retain the new value and release the old:
- (void)setEntryDate:(NSDate *)date
{
[date retain];
[entryDate release];
entryDate = date;
}
Congratulations! You have now completed converting the lottery project to a retain-counted application. Run the static analyzer on the application (Product -> Analyze); you should have zero issues.
Living with ARC
Although manual reference counting is fairly simple, it can be difficult to execute perfectly. At best, this leads to minor leaks but more typically results in crashes. At the end of Chapter 3, we saw that the static analyzer was able to find Objective-C memory errors in our code. Some clever engineers at Apple asked, “If we can find memory errors, why don’t we go ahead and fix them?” ARC is the result.
ARC is a compiler feature, based on the same technology that powers the static analyzer. When you compile your application, your use of Objective-C object pointers (references) is examined by the compiler, which then applies the same rules we described earlier in this chapter, retaining, releasing, and autoreleasing to ensure that the objects live as long as necessary and are deallocated when they are no longer needed.
Essentially, this means that all the memory-related changes we made to the lottery project were unnecessary under ARC. In fact, when using ARC, it is an error to call retain, release, or autorelease. With ARC, you will think less about retain counts and focus more on object relationships. Relationships are defined by references, which are simply object pointers. There are two types of references: strong and weak.
Strong References
By default, references are strong. If you assign an object to a strong reference, ARC assumes that you want that object to stick around and retains it implicitly. If that reference is changed to a new value, the old object is released and the new object retained, just like the setEntryDate: setter we wrote in the previous section. Thus, the same setter can be rewritten as follows, without any memory concerns:
- (void)setEntryDate:(NSDate *)date
{
entryDate = date;
}
ARC will take care of releasing any strong references in dealloc for you. You can still implement dealloc to take care of any other cleanup tasks.
Weak References
Weak references are similar to the old manual reference-counted pointers: There is no implicit retain; the pointer