ARC is supported in Xcode 4.2 and later OS X v10.6 and later (64-bit applications) and for iOS 4 and later. Weak references are not supported in OS X v10.6 and iOS 4. There is no ARC support in Xcode 4.1 and earlier.
ARC is a compiler feature, so followings:
- Its a COMPILE TIME memory management model. Its NOT A RUN TIME memory management model.
- Compiler adds retain, release and autorelease calls to our code at Compile time.
- Its not new memory model, no new memory mechanism, Its just do retain and release automatically.
- Compiler adds C functions for retain and release, it does not call retain and release methods. It calls below methods
- objc_retain(someValue);
- objc_release(someValue);
- objc_autorelease(someValue);
- Compiler also generates appropriate dealloc method for us if needed.
- Automates Objective-C objects only (i.e. NSObject based objects). Neither it automates malloc() and free() nor CoreFoundation() and CoreGraphics() etc. That means we have to use CFRetain, CFRelease as MRC (Manual Reference Counting) for other than NSObjects classes.
- There are three places which we can not consider for ARC and a user has to manage memory manually with retain and release (MRC):
- No heap scan for unused objects (Its not Garbage Collector).
- No whole app pauses.
- No non-deterministic release.
Ownership Type Qualifiers
- __strong =
- An object remains “alive” as long as there is a strong pointer to it.
- Retain their values.
- Its default attribute of a property so we never have to type it.
- Stack local variables, method parameters are __strong.
__weak = only available on iOS 5 and Mac OX 10.7.
- Specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.
- Don’t retain their values.
- Safely yield nil as soon as referenced object starts deallocating.
- NSWindow, NSViewController etc does not allow __weak references
__weak id obj = [NSObject new]; *** means ***
__weak id obj;
id temp = [NSObject new];
obj = id;
[id release];
We can modified out Non-ARC code if we want to use __weak with below C functions
- objc_loadWeak(&myWeakIvar);
- objc_storeWeak(&myWeakIvar, newValue);
- __unsafe_unretained = specifies a reference that does not keep the referenced object alive and is not set to nil when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.
- An alternative for __weak, aka assign kind of property.
- __autoreleasing = is used to denote arguments that are passed by reference (id *) and are autoreleased on return.
- for indirect pointers which are treated like autoreleased return values
Correct Way to declare variable - *** ClassName * qualifier variableName; ***
- MyClass * __weak myWeakReference;
- MyClass * __unsafe_unretained myUnsafeReference;
In some cases you can use __unsafe_unretained if the class isn’t __weak compatible. This can, however, become impractical for nontrivial cycles because it can be hard or impossible to validate that the __unsafe_unretained pointer is still valid and still points to the same object in question.
ARC & Blocks
- Blocks work best under ARC!
- Blocks always start out on the stack, must be copied when:
- Stored into instance variables or globals.
- Returned or indirectly assigned
- In ARC blocks are automatically copied, we don’t need to copy a block to retain it in heap.
__block objects variables are __strong by default under ARC.
__block objects variables are __unsafe_unretained by default under non-ARC. (Dangling Pointer)
Issue with ARC:
You CAN NOT give an accessor a name that begins with new. This in turn means that you can’t, for example, declare a property whose name begins with new unless you specify a different getter:
- Won’t work: @property NSString *newTitle;
- Works: @property (getter=theNewTitle) NSString *newTitle;
- Problem: Under ARC we may have issues with its strong reference behavior.
- Solution: we can convert objects into weak reference.
- 1. Either: __weak id objectName = self.
- 2. Or: __block __unsafe_unretained id objectName = self.
- Solution: we can convert objects into weak reference.
- The following is invalid in ARC init methods: [super init];
- The simple fix is to change it to: self = [super init];
- The proper fix is to do that, and check the result for nil before continuing:
- self = [super init];
- if (self) {
- …
Some Other Points:
- Using ARC, strong, weak, and autoreleasing stack variables are now implicitly initialized with nil.
- The new @autoreleasepool{} construct is about six times faster than NSAutoreleasePool object. @autoreleasepool{} even works in non-ARC code.
- Use Objective-C objects instead of structs. This is considered to be best practice anyway.
- In ARC Object Pointers must be initialized with nil.
- With ARC, instance variables are strong references by default—assigning an object to an instance variable directly does extend the lifetime of the object.
- Some new CF APIs __bridge, __bridge_retain, __bridge_transfer.
- Objects are often leaked when exceptions are thrown.
- We can not explicitly invoke dealloc, or implement or invoke retain, release, autorelease or retainCount. The prohibition extends to using @selector(retain), @selector(release) and so on.
Migrate your code to ARC
- Compile code with LLVM 3.0
- Use “Convert to Objective-C ARC” command in Xcode
- Fix issue until everything compiles
- Analyze code and fix issues
Use Compiler Flags to Enable and Disable ARC
You enable ARC using a new -fobjc-arc compiler flag. You can also choose to use ARC on a per-file basis if it’s more convenient for you to use manual reference counting for some files. For projects that employ ARC as the default approach, you can disable ARC for a specific file using a new -fno-objc-arc compiler flag for that file.
Object Graph Cycle
New Pointer - Zeroing Weak Pointer (References)
- Just like objects
- Non-retaining reference
- Drops to nil automatically
This does not transfer ownership.
- - (void)takeThisError:(NSError*)error; this means
- - (void)takeThisError:(__autoreleased NSError*)error;
Passing ownership is possible by using __strong
- (void)takeThisError:(__strong NSError*)error;