// *** before: ***
// the rule was memorised by hand: alloc, new, copy and retain give you an
// object you own, and you owe it exactly one release
@implementation Library
- (void)load {
Book *book = [[Book alloc] initWithTitle:@"Moby-Dick"];
[self.books addObject:book];
[book release]; // owned by alloc - released here
Book *found = [self.books objectAtIndex:0];
[found retain]; // not owned - retained to keep it
self.current = found;
[found release];
}
- (Book *)makeBook {
Book *book = [[Book alloc] init];
return [book autorelease]; // the caller does not own the result
}
- (void)dealloc {
[_books release];
[_current release];
[super dealloc]; // and the last line was always this
}
@end
// *** in version 2011: ***
// the compiler inserts retain, release and autorelease itself, at the same
// places a careful person would have put them
@implementation Library
- (void)load {
Book *book = [[Book alloc] initWithTitle:@"Moby-Dick"];
[self.books addObject:book]; // no release: the variable owns it
// until the end of the block
Book *found = self.books[0];
self.current = found; // the setter holds it by itself
}
- (Book *)makeBook {
return [[Book alloc] init]; // no autorelease either
}
// dealloc may be left out entirely; if it is written, it releases nothing
// and [super dealloc] is now forbidden
@end
// ⚠️ retain, release, autorelease and [super dealloc] became compile errors
// under ARC. ARC is not a garbage collector: it is the same counting, only
// written by the compiler, so a retain cycle still leaks