Explanation of strong and weak.
Strong: "keep this in the heap until I don't point to it anymore"
Weak: "keep this as long as someone else points to it strongly"
Difference
The difference is that an object will be deallocated as soon as there are no strong pointers to it. Even if weak pointers point to it, once the last strong pointer is gone, the object will be deallocated, and all remaining weak pointers will be zeroed out.
A weak reference does not extend the lifetime of the object it points to, and automatically becomes
nil
when there are no strong references to the object.
Note
Under ARC,
strong
is the default for object types.
Consider an example.
Imagine our object is a dog, and that the dog wants to run away (be deallocated).
Strong pointers are like a leash on the dog. As long as you have the leash attached to the dog, the dog will not run away. If five people attach their leash to one dog, (five strong pointers to one object), then the dog will not run away until all five leashes are detached.
Weak pointers, on the other hand, are like little kids pointing at the dog and saying "Look! A dog!" As long as the dog is still on the leash, the little kids can still see the dog, and they'll still point to it. As soon as all the leashes are detached, though, the dog runs away no matter how many little kids are pointing to it.
As soon as the last strong pointer (leash) no longer points to an object, the object will be deallocated, Transitioning to ARC Release Notes
Variable Qualifiers
You use the following lifetime qualifiers for variables just like you would, say,
const
.__strong |
__weak |
__unsafe_unretained |
__autoreleasing |
__strong
is the default. An object remains “alive” as long as there is a strong pointer to it.__weak
specifies a reference that does not keep the referenced object alive. A weak reference is set tonil
when there are no strong references to the object.__unsafe_unretained
specifies a reference that does not keep the referenced object alive and is not set tonil
when there are no strong references to the object. If the object it references is deallocated, the pointer is left dangling.__autoreleasing
is used to denote arguments that are passed by reference (id *
) and are autoreleased on return.
You should decorate variables correctly. When using qualifiers in an object variable declaration, the correct format is:
ClassName * qualifier variableName; |
for example:
MyClass * __weak myWeakReference; |
MyClass * __unsafe_unretained myUnsafeReference; |
Other variants are technically incorrect but are “forgiven” by the compiler. To understand the issue, see http://cdecl.org/.
Take care when using
__weak
variables on the stack. Consider the following example:NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; |
NSLog(@"string: %@", string); |
Although
string
is used after the initial assignment, there is no other strong reference to the string object at the time of assignment; it is therefore immediately deallocated. The log statement shows that string
has a null value. (The compiler provides a warning in this situation.)
You also need to take care with objects passed by reference. The following code will work:
NSError *error; |
BOOL OK = [myObject performOperationWithError:&error]; |
if (!OK) { |
// Report the error. |
// ... |
However, the error declaration is implicitly:
NSError * __strong e; |
and the method declaration would typically be:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error; |
The compiler therefore rewrites the code:
NSError * __strong error; |
NSError * __autoreleasing tmp = error; |
BOOL OK = [myObject performOperationWithError:&tmp]; |
error = tmp; |
if (!OK) { |
// Report the error. |
// ... |
The mismatch between the local variable declaration (
__strong
) and the parameter (__autoreleasing
) causes the compiler to create the temporary variable. You can get the original pointer by declaring the parameter id __strong *
when you take the address of a __strong
variable. Alternatively you can declare the variable as __autoreleasing
.and all weak pointers will be zeroed out.
ARC Uses a New Statement to Manage Autorelease Pools
Using ARC, you cannot manage autorelease pools directly using the
NSAutoreleasePool
class. Instead, you use @autoreleasepool
blocks:@autoreleasepool { |
// Code, such as a loop that creates a large number of temporary objects. |
} |
This simple structure allows the compiler to reason about the reference count state. On entry, an autorelease pool is pushed. On normal exit (break, return, goto, fall-through, and so on) the autorelease pool is popped. For compatibility with existing code, if exit is due to an exception, the autorelease pool is not popped.
This syntax is available in all Objective-C modes. It is more efficient than using the
NSAutoreleasePool
class; you are therefore encouraged to adopt it in place of using the NSAutoreleasePool
.Stack Variables Are Initialized with nil
Using ARC, strong, weak, and autoreleasing stack variables are now implicitly initialized with
nil
. For example:- (void)myMethod { |
NSString *name; |
NSLog(@"name: %@", name); |
} |
will log null for the value of name rather than perhaps crashing.
Use Compiler Flags to Enable and Disable ARC
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.
Enable ARC ->
-fobjc-arc
Disable ARC ->
-fno-objc-arc
Project -> Build Phases -> Compiler Sources -> Set Compiler flag for particular file.
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.Basic Memory Management Rules
The memory management model is based on object ownership. Any object may have one or more owners. As long as an object has at least one owner, it continues to exist. If an object has no owners, the runtime system destroys it automatically. To make sure it is clear when you own an object and when you do not, Cocoa sets the following policy:
- You own any object you createYou create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example,
alloc
,newObject
, ormutableCopy
). - You can take ownership of an object using retainA received object is normally guaranteed to remain valid within the method it was received in, and that method may also safely return the object to its invoker. You use
retain
in two situations: (1) In the implementation of an accessor method or aninit
method, to take ownership of an object you want to store as a property value; and (2) To prevent an object from being invalidated as a side-effect of some other operation (as explained in “Avoid Causing Deallocation of Objects You’re Using”). - When you no longer need it, you must relinquish ownership of an object you ownYou relinquish ownership of an object by sending it a
release
message or anautorelease
message. In Cocoa terminology, relinquishing ownership of an object is therefore typically referred to as “releasing” an object. - You must not relinquish ownership of an object you do not ownThis is just corollary of the previous policy rules, stated explicitly.
Comments
Post a Comment