Automatic Reference Counting


Published on

Slides from Automatic Reference Counting by Giuseppe Arici @ Pragma Night

Published in: Technology
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Automatic Reference Counting

  1. 1. AutomaticReference Counting Giuseppe Arici Pragma Night @ Talent Garden
  2. 2. Memory Management• Manual Reference Counting • Higher level abstraction than malloc / free • Straightforward approach, but must adhere to conventions and rules• Garbage Collection • Only available for OS X 10.5+, but depracated from 10.8+ • Not available on iOS due to performance concerns• Automatic Reference Counting (ARC) • Makes memory management the job of the compiler (and runtime) • Available for: partially iOS 4+ or OS X 10.6+ / fully iOS 5+ or OS X 10.7+ Pragma Night
  3. 3. Manual Reference Counting Reference Counting Pragma Night
  4. 4. Manual Reference Counting(Only) Objective-C objects are reference counted:• Objects start with retain count of 1 when created• Increased with retain• Decreased with release, autorelease• When count equals 0, runtime invokes dealloc 1 2 1 0 alloc retain release release dealloc Pragma Night
  5. 5. Objects you create For objects you create with [[SomeClass alloc] init] or [myInstance copy] (without autoreleasing):• Retain should not need to be called• Release when you are done using it in the {code block}- (void)someMethod { NSObject *localObject = [[NSObject alloc] init]; _instanceArray = [[NSArray alloc] initWithObjects:localObject, nil]; [localObject release];}- (void)dealloc { [_instanceVariable release]; [super dealloc];} Pragma Night
  6. 6. Objects you don’t create For objects you don’t create (e.g. get from methods):• Retain only when saving to instance (or static) variable• Release only if you retained it by saving it (as in above case)- (void)someMethod { id localObject = [anArray objectAtIndex:0]; _instanceVariable = [localObject retain];}- (void)dealloc { [_instanceVariable release]; [super dealloc];} Pragma Night
  7. 7. AutoreleaseWhat if you create an object and you are returning it from amethod, how would you be able to release it?- (NSArray *)objects { NSArray *localArray = [[NSArray alloc] init]; ✇} return localArray; Leak ! ☠- (NSArray *)objects { NSArray *localArray = [[NSArray alloc] init]; return [localArray release];} Crash !- (NSArray *)objects { NSArray *localArray = [[NSArray alloc] init]; ☺ return [localArray autorelease];} Enjoy ! Pragma Night
  8. 8. Autorelease• Instead of explicitly releasing something, you mark it for a later release• An object called autorelease pool manages a set of objects to release when the pool is released• Add an object to the release pool by calling autorelease@autoreleasepool { // code goes here}NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];// code goes here[pool release]; Pragma Night
  9. 9. Autorelease• Autorelease is NOT a Garbage Collector ! It is deterministic ⌚• Objects returned from methods are understood to be autoreleased if name is not in implicit retained set (alloc/new/copy/mutableCopy/init)• If you spawn your own thread, you’ll have to create your own NSAutoreleasePool• Stack based: autorelease pools can be nested Friday Q&A 2011-09-02: Lets Build NSAutoreleasePool Pragma Night
  10. 10. The Memory Management Rule Everything that increases the retain count withalloc, [mutable]copy[WithZone:], new or retainis in charge of the corresponding [auto]release. From C++ to Objective-C Pragma Night
  11. 11. Automatic Reference Counting “Automatic Reference Counting (ARC) in Objective-C makes memory management the job of the compiler. By enabling ARC with the new Apple LLVM compiler, you will never need to type retain or release again, dramatically simplifying the development process, while reducing crashes and memory leaks. The compiler has a complete understanding of your objects, and releases each object the instant it is no longer used, so apps run as fast as ever, with predictable, smooth performance.” (Apple, “iOS 5 for developers” – Pragma Night
  12. 12. Automatic Reference Counting• The Rule is still valid, but it is managed by the compiler• No more retain, release, autorelease nor dealloc• New lifetime qualifiers for objects, which includes zeroing weak references (only available on iOS 5+ & OS X 10.7+)• Apple provides a migration tool which is build into Xcode Pragma Night
  13. 13. ARC Settings: Project | File Pragma Night
  14. 14. Requirements• iOS 5+ & OS X 10.7+ Full Support :)• iOS 4 & OS X 10.6 (64-bit) No Runtime :( Pragma Night
  15. 15. How it works !? ARC consists of 2 main componentsFrontend Compiler Optimizer Pragma Night
  16. 16. ARC Frontend Compiler• For every local variable inserts retain and [auto]release appropriately in the block scope { }• For every owned instance variable inserts release appropriately in the dealloc method• Call the [super dealloc] in dealloc method• Generates errors when a variable ownership is not set correctly Pragma Night
  17. 17. Method Family / Ownership Method Name Family Object Ownership Actionalloc/new/copy/mutableCopy/init Create and have ownership of it retain Take ownership of it release Relinquish it dealloc Dispose of it Everything Else No ownership ! alloc/new/copy/mutableCopy/init “ The Implicit Retained Set ” Pragma Night
  18. 18. ARC Frontend Compiler 1/3- (void)someMethod { Foo *foo = [[Foo alloc] init]; [foo bar];}- (void)someMethod { Foo *foo = [[Foo alloc] init]; [foo bar]; [foo release];}- (void)someMethod { Foo *foo = [[Foo alloc] init]; [foo bar]; obj_release(foo);} Pragma Night
  19. 19. ARC Frontend Compiler 2/3- (void)someMethod { Foo *localFoo = [self foo]; [localFoo bar]; = [Builder newFoo]; [localFoo bar]; ☠} Crash !- (void)someMethod { Foo *localFoo = objc_retain([self foo]); [localFoo bar]; = [Builder newFoo]; [localFoo bar]; ☺} objc_release(localFoo); Enjoy ! Pragma Night
  20. 20. ARC Frontend Compiler 3/3- (Foo *) foo{ return _foo;}- (Foo *) foo{ return [[_foo retain] autorelease];}- (Foo *) foo{ return objc_retainAutoreleaseReturnValue(_foo);} Pragma Night
  21. 21. ARC Optimizer• Optimize the retain and release statements by removing them if they are inserted multiple times by the ARC Frontend Compiler• Ensures that performance is not affected by calling retain and release multiple times Pragma Night
  22. 22. ARC Optimizer 1/2 retain autorelease retain releasestack Pragma Night
  23. 23. ARC Optimizer 1/2 retain releasestack Pragma Night
  24. 24. ARC Optimizer 2/2- (Foo *) foo called method{ return objc_retainAutoreleaseReturnValue(_foo);} Autorelease Pool- (void)someMethod { Foo *f = objc_retainAutoreleasedReturnValue([self foo]); [f bar]; = [Builder newFoo]; [f bar]; objc_release(f);} caller method Pragma Night
  25. 25. Variable Ownership Qualifiers• __strong (default)• __weak• __unsafe_unretained• __autoreleasing Only For Object Type Variables ! ( id | AnyClass : NSObject ) Pragma Night
  26. 26. Retain Cycles 1/5 Parent Child __strong _view +1 +1 _delegate __strong Controller Viewas View Delegate Pragma Night
  27. 27. Retain Cycles 2/5 Parent Child __strong _view = +1 _delegate __unsafe_unretained Controller Viewas View Delegate Pragma Night
  28. 28. Retain Cycles 3/5 Parent Child __strong _view = +1 _delegate __weak Controller Viewas View Delegate Pragma Night
  29. 29. Retain Cycles 4/5dealloc Parent Child release ☠ _view New with ARC in iOS 5+ & OS X 10.7+ = _delegate __weak Controller View ☺nil as View Delegate Pragma Night
  30. 30. Retain Cycles 5/5 Pragma Night
  31. 31. __strong/* ARC */{ id __strong obj1 = [[NSObject alloc] init]; id obj2 = [[NSObject alloc] init];}/* not-ARC */{ id obj1 = [[NSObject alloc] init]; [obj1 release];}• Strong reference for the object• Default for ‘id’ and Object Type Variables ! Pragma Night
  32. 32. __weak/* ARC */{ id __strong obj1 = [[NSObject alloc] init]; id __weak obj2 = obj1;}/* not-ARC */{ id obj1 = [[NSObject alloc] init]; id obj2 = obj1; [obj1 release];}• No ownership of the object• When discarded, the variable is assigned to nil Pragma Night
  33. 33. __unsafe_unretained/* ARC */{ id __unsafe_unretained obj = [[NSObject alloc] init];}Assigning retained object to unsafe_unretained variable; object will be released after assignment [-Warc-unsafe-retained-assign]• UNSAFE !• You must take care of the variables manually• __weak only for iOS 5+ / OSX 10.7+ Pragma Night
  34. 34. __autoreleasing @autoreleasepool { id __strong obj = [NSMutableArray array]; } - (BOOL) performWithError:(NSError **)error; - (BOOL) perfomrWithError:(NSError * __autoreleasing *)error;• Pointer to ‘id’ or to ‘Object Type Variables Pointer’ is qualified with __autoreleasing as default Pragma Night
  35. 35. Variables Initialization /* ARC */ id __strong obj1; id __weak obj2; id __unsafe_unretained obj3; id __autoreleasing obj4; /* not-ARC */ id __strong obj1 = nil; id id __weak obj2 = nil; __unsafe_unretained obj3; ☠ id __autoreleasing obj4 = nil; Crash !• Any variables that are qualified with __strong, __weak and __autoreleasing are initialized with nil Pragma Night
  36. 36. PropertyObject Property Modifier Variable Ownership Qualifier assign __unsafe_unretained unsafe_unretained __unsafe_unretained weak __weak retain __strong strong __strong copy __strong * * Note: new copied object is assigned Pragma Night
  37. 37. Property• Same ownership rules as instance variables• Manually declared instance variables has to have the same ownership qualifier as the property• Copy: copies the object by using copyWithZone Pragma Night
  38. 38. Coding With ARC RulesWhat is forbidden ?What can be done but with care ?What is mandatory ? Pragma Night
  39. 39. Rule 01/12 • Forget about using retain, release, retainCount and autorelease { id obj1 = [[NSObject alloc] init]; /* ... */ [obj1 release]; }error: ARC forbids explicit message send of release [obj release]; Pragma Night
  40. 40. Rule 02/12 • Forget about using NSAllocateObject, NSDeallocateObject, NSZone & Co. /* NSObject.h */ /***********! Object Allocation / Deallocation! *******/ ! FOUNDATION_EXPORT id NSAllocateObject(Class, NSUInteger, NSZone *) NS_AUTOMATED_REFCOUNT_UNAVAILABLE;error: NSAllocateObject is unavailable: not available in automatic reference counting mode Pragma Night
  41. 41. Rule 03/12 • Forget about using NSAutoreleasePool Use @autoreleasepool { ... } Instead NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; /* ... */ [pool drain]; // [pool release];error: NSAutoreleasePool is unavailable: not available in automatic reference counting mode Pragma Night
  42. 42. Rule 04/12 • Forget about calling super dealloc explicitly - (void) dealloc { free(buffer); [super dealloc]; }error: ARC forbids explicit message send of dealloc [super dealloc]; not available in automatic reference counting mode Pragma Night
  43. 43. Rule 05/12 • Object Type Variables Cannot Be Members of struct or union in C struct Data { NSMutableArray *array; };error: ARC forbids Objective-C objs in structs or unions NSMutableArray *array; Pragma Night
  44. 44. Rule 06/12• Exceptions use must be exceptional • For performance purpose, ARC code leaks on exceptions • In Obj-C ARC is not exception-safe for normal releases by default • -fobjc-arc-exceptions / -fno-objc-arc-exceptions: enable / disable • In Obj-C++ -fobjc-arc-exceptions is enabled by default Pragma Night
  45. 45. Rule 07/12• IBOutlet must be declared as weak • Outlets should be defined as declared properties • Outlets should generally be weak • Top-level objects (or, in iOS, a storyboard scene) should be strong Resource Programming Guide Pragma Night
  46. 46. Rule 08/12• Be careful with performSelector#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-performSelector-leaks"[self performSelector:@selector(someMethod)];#pragma clang diagnostic pop Pragma Night
  47. 47. Rule 09/12• Follow the naming rule for methods related to object creation: implicit retained set • If begins { alloc/new/copy/mutableCopy }, the caller has ownership • If begins { init }, the method has to: * • be an instance method • return an object of type ‘id’ or an object of type of its [super|sub]class • return an object not registered in autoreleasepool: the caller has ownership- (id)init...; * A special case: “ + (void) initialize ” Pragma Night
  48. 48. False Positive-(NSString*) copyRightString;-(NSString*) copyRightString NS_RETURNS_NOT_RETAINED;• NS_RETURNS_RETAINED• NS_RETURNS_NOT_RETAINEDThis macro is ONLY to be used in exceptional circumstances, not to annotate functions which conform to the Cocoa naming rules. Pragma Night
  49. 49. Rule 10/12• Switch cases must be wrapped in scope with { ... }switch (value){ case 0: { NSObject *obj= [[NSObject alloc] init]; NSLog(@"obj for value 0: %@", obj); } break;} Pragma Night
  50. 50. Rule 11/12• The old style singleton which redefines retain and release is not ARC compatible• Singletons should be redefined with dispatch_oncestatic Foo *sharedInstance;+ (id)sharedInstance { static dispatch_once_t predicate; dispatch_once(&predicate, ^{ sharedInstance = [[Foo alloc] init]; }); return sharedInstance;} Pragma Night
  51. 51. Rule 12/12 • id and void * Have to Be Cast Explicitly id object = [[NSObject alloc] init]; void *pointer = object;Error: implicit conversion of a non-Objective-C pointer type void * to id is disallowed with ARC Pragma Night
  52. 52. ( _bridge cast )id object1 = [[NSObject alloc] init];void *pointer = (__bridge void *)object1;id object2 = (__bridge id)pointer;• More dangerous than an __unsafe_unretained qualified variable !• You have to manage ownership of the object yourself carefully or it crashes Pragma Night
  53. 53. ( __bridge_retained cast )/* ARC */id object = [[NSObject alloc] init];void *pointer = (__bridge_retained void *)object;/* not-ARC */id object = [[NSObject alloc] init];void *pointer = object;[(id)pointer retain];• From ARC to Core Foundation• __bridge_retained cast will retain the object just after the assignment is done Pragma Night
  54. 54. ( __bridge_transfer cast )/* ARC */void *pointer = &bytes;id object = (__bridge_transfer id)pointer;/* not-ARC */id object = (id)pointer;[object retain];[(id)pointer release];• From Core Foundation to ARC• __bridge_transfer cast will release the object just after the assignment is done Pragma Night
  55. 55. Toll-Free Bridging/* NSObject.h */// After using a CFBridgingRetain on an NSObject, the caller// must take responsibility for calling CFRelease at an// appropriate timeNS_INLINE CF_RETURNS_RETAINED CFTypeRefCFBridgingRetain(id X){ return (__bridge_retained CFTypeRef)X;}NS_INLINE idCFBridgingRelease(CFTypeRef CF_CONSUMED X){ return (__bridge_transfer id)X;} Pragma Night
  56. 56. ARC MACRO// define some LLVM3 macros if the code is// compiled with a different compiler (ie LLVMGCC42)#ifndef __has_ feature#define __has_feature(x) 0#endif#ifndef __has_extension// Compatibility with pre-3.0 compilers#define __has_extension __has_feature#endif#if __has_feature(objc_arc) && __clang_major__ >= 3#define ARC_ENABLED 1#endif Check @ compile-time if ARC is enabled Pragma Night
  57. 57. tl;dr What Is ARC ?• Automatic memory management of Obj-C objects • Compiler obeys and enforces existing conventions• Full interoperability with manual retain and release• New runtime features • Weak pointers • Advanced performance optimizations Pragma Night
  58. 58. tl;dr What ARC Is NOT ?• No new runtime memory model• No automation for malloc/free, CF, etc.• No garbage collector • No heap scans • No whole app pauses • No non-deterministic releases Pragma Night
  59. 59. ARC References• Clang: Automatic Reference Counting documentation• Apple: Transitioning to ARC Release Notes• Apple: Xcode New Features User Guide: Automatic Reference Counting• WWDC 2011 – Session 323 – Introducing Automatic Reference Counting• WWDC 2012 – Session 406/416 – Adopting Automatic Reference Counting• Mike Ash: Friday Q&A about Automatic Reference Counting• Mike Ash: Zeroing weak references without ARC Pragma Night
  60. 60. ARC Books Pragma Night
  61. 61. NSLog(@”Thank you!”); Pragma Night