Share
Embed
Automatic Reference Counting
ARC makes Objective-C development so much easier and enjoyable by eliminating almost all need to manually handle memory management.
Rob Brown
February 09, 2012
Transcript
34 slides
-
What is ARC? Automatic Reference Counting Similar to using smart
pointers Never need to call -release or -autorelease More efficient than garbage collection No more memory leaks! Doesn’t handle retain loops -
What is ARC? Includes a weak reference system (Lion/iOS 5.0+)
ARC code works with non-ARC code and vice versa Xcode 4.2+ only -
Manual Reference Counting Just to help you appreciate ARC... Retain:
+1 retain count (claim ownership) Release: -1 retain count (revoke ownership) Autorelease: Ownership is transferred to latest autorelease pool on the current thread When retain count reaches 0, the object is deleted. With ARC you ignore all of this -
New Rules You cannot explicitly invoke dealloc, or implement or
invoke retain, release, retainCount, or autorelease. The prohibition extends to using @selector(retain), @selector(release), and so on. -
New Rules You may implement a dealloc method if you
need to manage resources other than releasing instance variables. You do not have to (indeed you cannot) release instance variables, but you may need to invoke [systemClassInstance setDelegate:nil] on system classes and other code that isn’t compiled using ARC. -
New Rules Custom dealloc methods in ARC do not require
a call to [super dealloc] (it actually results in a compiler error). The chaining to super is automated and enforced by the compiler. You can still use CFRetain, CFRelease, and other related functions with Core Foundation-style objects. -
New Rules You cannot use NSAllocateObject or NSDeallocateObject. You create
objects using alloc; the runtime takes care of deallocating objects. You cannot use object pointers in C structures. Rather than using a struct, you can create an Objective-C class to manage the data instead. -
New Rules There is no casual casting between id and
void *. You must use special casts that tell the compiler about object lifetime. You need to do this to cast between Objective-C objects and Core Foundation types that you pass as function arguments. -
New Rules Cannot use NSAutoreleasePool objects. ARC provides @autoreleasepool blocks
instead. These have an advantage of being more efficient than NSAutoreleasePool. You cannot use memory zones. There is no need to use NSZone any more—they are ignored by the modern Objective-C runtime anyway. -
New Rules To allow interoperation with manual retain-release code, ARC
imposes some constraints on method and variable naming: You cannot give a property a name that begins with new. -
New Rules Summary: ARC does a lot of stuff for
you. Just write your code and trust ARC to do the right thing. If you write C code, then you actually have to do some work. -
Old way: NSAutoreleasePool * pool = [NSAutoreleasePool new]; NSArray *
comps = [NSArray arrayWithObjects:@"BYU", @"CocoaHeads", nil]; NSString * path = [NSString pathWithComponents:comps]; NSURL * url = [[NSURL alloc] initWithPath:path]; // Do something with the URL. [url release]; [pool drain]; ARC way: @autoreleasepool { // This is cool! NSArray * comps = [NSArray arrayWithObjects:@"BYU", @"CocoaHeads", nil]; NSString * path = [NSString pathWithComponents:comps]; NSURL * url = [[NSURL alloc] initWithPath:path]; // Do something with the URL. // Hey look! No release! } // Automatic drain! -
Automatic Conversion 1.Edit > Refactor > Convert to Objective-C ARC
2.Select the files you want to convert (probably all) 3.Xcode will let you know if it can’t convert certain parts You may want to continue on errors Xcode > Preferences > General > Continue building after errors -
Weak reference doesn’t increment retain count Weak reference is nilled
when the object is dealloc’d Adds some overhead due to bookkeeping Great for delegates @property(nonatomic, weak) id delegate; iOS 5.0+ Weak Referencing -
IBOutlets Weak reference: Used only with non- top-level IBOutlets Automatically
nils IBOutlet in low memory condition Requires some extra overhead Strong reference: Must be used for top- level IBOutlets May be used for non- top-level IBOutlets Manually nil IBOutlet in -viewDidUnload -
Lifetime Qualifiers __strong A retained reference (default) __weak Uses weak
reference system Jedi Level -
What About C? ARC does not manage memory for C
You must call free() for every malloc() Core Foundation objects use CFRelease() Toll-free bridging requires an extra keyword Jedi Level -
Bridging __bridge Straight bridge cast __bridge_transfer -1 to the retain
count __bridge_retained +1 to the retain count Jedi Level -
Bridging Made Easy The casts are hard to remember Use
these macros instead: CFBridgingRetain(obj) = ARC to C CFBridgingRelease(obj) = C to ARC Jedi Level -
Disabling ARC ARC can be disabled on a file-level. Project
file > Main target > Build phases > Compile sources > Add compiler flag “-fno-objc-arc” If ARC is not on by default, it can be turned on manually with “-fobjc-arc” Jedi Level -
Blocks // WARNING: Retain loop! // The static analyzer will
warn you about this. [self setBlock:^{ [self doSomething]; [_ivar doSomethingElse]; // Implicitly self->_ivar } Jedi Level -
Blocks // No retain loop __block __unsafe_unretained id unretainedSelf =
self; [self setBlock:^{ [unretainedSelf doSomething]; [[unretainedSelf var] doSomethingElse]; } Jedi Level -
Blocks // Better alternative (iOS 5.0+) __weak id weakSelf =
self; [self setBlock:^{ [weakSelf doSomething]; [[weakSelf var] doSomethingElse]; } Jedi Level -
Return by Reference Return by reference is fairly common, especially
with NSError. Example: -(BOOL)save:(NSError *__autoreleasing*)outError; Jedi Level -
Return by Reference // What you write NSError * error
= nil; // Implicitly __strong. if (![self save:&error]) { // An error occurred. } Jedi Level -
Return by Reference // What ARC writes NSError * __strong
error = nil; NSError * __autoreleasing tmp = error; if (![self save:&tmp]) { // An error occurred. } Jedi Level -
Return by Reference // This isn’t a big deal, but
it avoids the temporary variable NSError * __autoreleasing error = nil; if (![self save:&error]) { // An error occurred. } Jedi Level -
Want to Learn More? WWDC 2011: Session 323 Transitioning to
ARC Release Notes