automatic reference counting

61
Pragma Night @ Talent Garden Automatic Reference Counting Giuseppe Arici

Post on 21-Oct-2014

1.962 views

Category:

Technology


2 download

DESCRIPTION

Slides from Automatic Reference Counting by Giuseppe Arici @ Pragma Night

TRANSCRIPT

Page 1: Automatic Reference Counting

Pragma Night @ Talent Garden

Automatic Reference Counting

Giuseppe Arici

Page 2: Automatic Reference Counting

Pragma Night

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+

Page 3: Automatic Reference Counting

Pragma Night

Manual Reference Counting

Reference Counting

Page 4: Automatic Reference Counting

Pragma Night

Manual Reference Counting

retain

2

alloc

1

release

1

release

0

(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

dealloc

Page 5: Automatic Reference Counting

Pragma Night

Objects you createFor 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];}

Page 6: Automatic Reference Counting

Pragma Night

Objects you don’t createFor 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];}

Page 7: Automatic Reference Counting

Pragma Night

AutoreleaseWhat if you create an object and you are returning it from a method, how would you be able to release it?

- (NSArray *)objects { NSArray *localArray = [[NSArray alloc] init]; return [localArray autorelease];}

- (NSArray *)objects { NSArray *localArray = [[NSArray alloc] init]; return [localArray release];}

- (NSArray *)objects { NSArray *localArray = [[NSArray alloc] init]; return localArray;}

✇Leak !

☠Crash !

☺Enjoy !

Page 8: Automatic Reference Counting

Pragma Night

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];

Page 9: Automatic Reference Counting

Pragma Night

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: Let's Build NSAutoreleasePoolhttp://www.mikeash.com/pyblog/friday-qa-2011-09-02-lets-build-nsautoreleasepool.html

Page 11: Automatic Reference Counting

Pragma Night

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” – http://developer.apple.com/technologies/ios5)

Page 12: Automatic Reference Counting

Pragma Night

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

Page 13: Automatic Reference Counting

Pragma Night

ARC Settings: Project | File

Page 14: Automatic Reference Counting

Pragma Night

Requirements

• iOS 5+ & OS X 10.7+ Full Support :)

• iOS 4 & OS X 10.6 (64-bit) No Runtime :(

Page 15: Automatic Reference Counting

Pragma Night

How it works !?

ARC consists of 2 main components

Frontend Compiler Optimizer

Page 16: Automatic Reference Counting

Pragma Night

• 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

ARC Frontend Compiler

Page 17: Automatic Reference Counting

Pragma Night

Method Family / Ownership

Method Name Family Object Ownership Action

alloc/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 !

Method Name Family Object Ownership Action

alloc/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 ”

Page 18: Automatic Reference Counting

Pragma Night

ARC Frontend Compiler 1/3

- (void)someMethod { Foo *foo = [[Foo alloc] init]; [foo bar]; [foo release];}

- (void)someMethod { Foo *foo = [[Foo alloc] init]; [foo bar];

}

- (void)someMethod { Foo *foo = [[Foo alloc] init]; [foo bar]; obj_release(foo);}

Page 19: Automatic Reference Counting

Pragma Night

ARC Frontend Compiler 2/3- (void)someMethod { Foo *localFoo = [self foo]; [localFoo bar];

self.foo = [Builder newFoo]; [localFoo bar];

}

- (void)someMethod { Foo *localFoo = objc_retain([self foo]); [localFoo bar];

self.foo = [Builder newFoo]; [localFoo bar]; objc_release(localFoo);}

☠Crash !

☺Enjoy !

Page 20: Automatic Reference Counting

Pragma Night

ARC Frontend Compiler 3/3

- (Foo *) foo{ return [[_foo retain] autorelease];}

- (Foo *) foo{ return _foo;}

- (Foo *) foo{ return objc_retainAutoreleaseReturnValue(_foo);}

Page 21: Automatic Reference Counting

Pragma Night

• 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

ARC Optimizer

Page 22: Automatic Reference Counting

Pragma Night

ARC Optimizer 1/2

retainautoreleaseretainrelease

retain

releasestack

Page 23: Automatic Reference Counting

Pragma Night

ARC Optimizer 1/2

retain

releasestack

Page 24: Automatic Reference Counting

Pragma Night

ARC Optimizer 2/2- (Foo *) foo{ return objc_retainAutoreleaseReturnValue(_foo);}

- (void)someMethod { Foo *f = objc_retainAutoreleasedReturnValue([self foo]); [f bar];

self.foo = [Builder newFoo]; [f bar]; objc_release(f);}

called method

caller method

Autorelease Pool

Page 25: Automatic Reference Counting

Pragma Night

Variable Ownership Qualifiers

• __strong (default)

• __weak

• __unsafe_unretained

• __autoreleasing

Only For Object Type Variables !( id | AnyClass : NSObject )

Page 26: Automatic Reference Counting

Pragma Night

Retain Cycles 1/5

Child

View

Parent

Controller

__strong

+1_view

__strong

as View Delegate

+1_delegate

Page 27: Automatic Reference Counting

Pragma Night

Retain Cycles 2/5

Child

View

Parent

Controller

__strong

+1_view

__unsafe_unretained

as View Delegate

=_delegate

Page 28: Automatic Reference Counting

Pragma Night

Retain Cycles 3/5

Child

View

Parent

Controller

__strong

+1_view

__weak

as View Delegate

=_delegate

Page 29: Automatic Reference Counting

Pragma Night

release

Retain Cycles 4/5

Child

View

Parent

Controller

=☠_view

__weak

as View Delegate

_delegate

dealloc

☺nil

New with ARC iniOS 5+ & OS X 10.7+

_view

_delegate

Page 30: Automatic Reference Counting

Pragma Night

Retain Cycles 5/5

Page 31: Automatic Reference Counting

Pragma Night

__strong

/* not-ARC */{ id obj1 = [[NSObject alloc] init]; [obj1 release];}

/* ARC */{ id __strong obj1 = [[NSObject alloc] init]; id obj2 = [[NSObject alloc] init];}

• Strong reference for the object

• Default for ‘id’ and Object Type Variables !

Page 32: Automatic Reference Counting

Pragma Night

__weak

/* not-ARC */{ id obj1 = [[NSObject alloc] init]; id obj2 = obj1; [obj1 release];}

/* ARC */{ id __strong obj1 = [[NSObject alloc] init]; id __weak obj2 = obj1;}

• No ownership of the object

• When discarded, the variable is assigned to nil

Page 33: Automatic Reference Counting

Pragma Night

__unsafe_unretained/* ARC */{ id __unsafe_unretained obj = [[NSObject alloc] init];}

• UNSAFE !

• You must take care of the variables manually

• __weak only for iOS 5+ / OSX 10.7+

Assigning retained object to unsafe_unretained variable; object will be released after assignment [-Warc-unsafe-retained-assign]

Page 34: Automatic Reference Counting

Pragma Night

__autoreleasing

- (BOOL) performWithError:(NSError **)error;

- (BOOL) perfomrWithError:(NSError * __autoreleasing *)error;

@autoreleasepool{ id __strong obj = [NSMutableArray array];}

• Pointer to ‘id’ or to ‘Object Type Variables Pointer’ is qualified with __autoreleasing as default

Page 35: Automatic Reference Counting

Pragma Night

Variables Initialization

/* not-ARC */id __strong obj1 = nil;id __weak obj2 = nil;id __unsafe_unretained obj3;id __autoreleasing obj4 = nil;

/* ARC */id __strong obj1;id __weak obj2;id __unsafe_unretained obj3;id __autoreleasing obj4;

• Any variables that are qualified with __strong, __weak and __autoreleasing are initialized with nil

☠Crash !

Page 36: Automatic Reference Counting

Pragma Night

Property

* Note: new copied object is assigned

*

Object Property Modifier Variable Ownership Qualifier

assign __unsafe_unretained

unsafe_unretained __unsafe_unretained

weak __weak

retain __strong

strong __strong

copy __strong

Page 37: Automatic Reference Counting

Pragma Night

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

Page 38: Automatic Reference Counting

Pragma Night

Coding With ARC Rules

What is forbidden ?

What can be done but with care ?

What is mandatory ?

Page 39: Automatic Reference Counting

Pragma Night

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];

Page 40: Automatic Reference Counting

Pragma Night

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

Page 41: Automatic Reference Counting

Pragma Night

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

Page 42: Automatic Reference Counting

Pragma Night

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

Page 43: Automatic Reference Counting

Pragma Night

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;

Page 44: Automatic Reference Counting

Pragma Night

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

Page 45: Automatic Reference Counting

Pragma Night

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

Page 46: Automatic Reference Counting

Pragma Night

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

Page 47: Automatic Reference Counting

Pragma Night

Rule 09/12

• Follow the naming rule for methods relatedto 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 ”

*

Page 48: Automatic Reference Counting

Pragma Night

False Positive

-(NSString*) copyRightString NS_RETURNS_NOT_RETAINED;

-(NSString*) copyRightString;

• NS_RETURNS_RETAINED

• NS_RETURNS_NOT_RETAINED

This macro is ONLY to be used in exceptional circumstances, not to annotate functions which conform to the Cocoa naming rules.

Page 49: Automatic Reference Counting

Pragma Night

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;}

Page 50: Automatic Reference Counting

Pragma Night

Rule 11/12

• The old style singleton which redefines retain and release is not ARC compatible

• Singletons should be redefined with dispatch_once

static Foo *sharedInstance;

+ (id)sharedInstance { static dispatch_once_t predicate; dispatch_once(&predicate, ^{ sharedInstance = [[Foo alloc] init]; }); return sharedInstance;}

Page 51: Automatic Reference Counting

Pragma Night

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

Page 52: Automatic Reference Counting

Pragma Night

( _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

Page 53: Automatic Reference Counting

Pragma Night

( __bridge_retained cast )

/* not-ARC */id object = [[NSObject alloc] init];void *pointer = object;[(id)pointer retain];

/* ARC */id object = [[NSObject alloc] init];void *pointer = (__bridge_retained void *)object;

• From ARC to Core Foundation

• __bridge_retained cast will retain the object just after the assignment is done

Page 54: Automatic Reference Counting

Pragma Night

( __bridge_transfer cast )

/* not-ARC */id object = (id)pointer;[object retain];[(id)pointer release];

/* ARC */void *pointer = &bytes;id object = (__bridge_transfer id)pointer;

• From Core Foundation to ARC

• __bridge_transfer cast will release the object just after the assignment is done

Page 55: Automatic Reference Counting

Pragma Night

Toll-Free Bridging

/* NSObject.h */

// After using a CFBridgingRetain on an NSObject, the caller // must take responsibility for calling CFRelease at an // appropriate time

NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetain(id X) { return (__bridge_retained CFTypeRef)X;}

NS_INLINE id CFBridgingRelease(CFTypeRef CF_CONSUMED X){ return (__bridge_transfer id)X;}

Page 56: Automatic Reference Counting

Pragma Night

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

Page 57: Automatic Reference Counting

Pragma Night

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

Page 58: Automatic Reference Counting

Pragma Night

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

Page 60: Automatic Reference Counting

Pragma Night

ARC Books