I know the definition of unsafe_unretained
.
So i don't expect anyone to write its definition.
I want to know its use with example, and how it works with memory management.
I know the definition of unsafe_unretained
.
So i don't expect anyone to write its definition.
I want to know its use with example, and how it works with memory management.
unsafe_unretained
only exists in ARC (Automatic Reference Counting). It works like assign
in MRC (Manual Reference Counting). These properties won't be retained. Usually, you'd want to use such properties for delegates, because they don't need an owner which retains them.
weak
properties are like unsafe_unretained
, except that they work a bit smarter. When the object assigned to the property is released, a weak reference automatically becomes nil
, to avoid crashes when sending messages to that object (its memory address).
unsafe_unretained
properties don't do this. They will always hold on to the memory address (unless you manually change it) assigned to it, regardless of the object associated to that address. Weak references can prevent crashes in such a case, but the result still won't be as expected. If your code is organized and well-written, this shouldn't happen.
So why would you use unsafe_unretained
instead of weak
? Weak references are only available on iOS 5 and higher, so if you're building an ARC app targeting iOS 4, you need to use unsafe_unretained
properties. And again, sending messages to a released property isn't anything you want to have in any code. If your code is well organized then you shouldn't have any problems with this.
Previously to ARC, one might specify a delegate or other reference-to-parent property as assign
to prevent retain cycles. With the introduction of ARC and the newer compilers you would instead use unsafe_unretained
.
So you use it any time you do not need ownership of the reference, and when you don't need or want to use the new weak
reference type (which nulls out the reference when it is deallocated).
Here is a specific use case for unsafe_unretained. Say two classes reference each other, one direction being strong and the other direction weak. During dealloc of the first class the weak reference to it from the second class will already be nil, preventing proper cleanup to take place. Replacing the weak reference with an unsafe_unretained reference will solve this issue. See the code sample below:
@class Foo;
@interface Bar: NSObject
//Replacing weak with unsafe_unretained prevents this property from becoming nil during Foo.dealloc
@property (nonatomic, weak) Foo *foo;
- (id)initWithFoo:(Foo *)foo;
@end
@interface Foo : NSObject
@property (nonatomic, strong) Bar *bar;
- (void)startObserving;
- (void)endObserving;
@end
@implementation Bar
- (id)initWithFoo:(Foo *)foo {
if ((self = [super init])) {
self.foo = foo;
//Start observing
[self.foo startObserving];
}
return self;
}
- (void)dealloc {
//Since foo is a weak property, self.foo may actually be nil at this point! See dealloc of class Foo.
[self.foo endObserving];
}
@end
@implementation Foo
- (id)init {
if ((self = [super init])) {
self.bar = [[Bar alloc] initWithFoo:self];
}
return self;
}
- (void)dealloc {
//This will trigger the deallocation of bar. However, at this point all weak references to self will return nil already!
self.bar = nil;
//endObserving is never called, because Bar.foo reference was already nil.
}
- (void)startObserving {
NSLog(@"Start observing");
}
- (void)endObserving {
NSLog(@"End observing");
}
@end
unsafe_unretained
does not interact with memory management at all. In ARC, the following code
{
__strong id obj = someObject;
obj = someOtherObject;
}
is equivalent to
{
id obj = [someObject retain];
[obj release];
obj = [someOtherObject retain];
[obj release];
}
in a non-ARC environment. So strong references keep the object alive. If you assign them a reference to another object, the old reference is first released. The same thing happens if such a reference goes out of scope. Note that references are strong by default, so usually you never have to use __strong
unless you want to emphasize that a variable is strong.
A weak reference won't keep the object alive and becomes nil
if the retain count of the object last assigned to it becomes zero.
__weak id wobj = nil;
{
__strong id obj = [Object new];
wobj = obj;
// wobj points to the same object as obj
}
// wobj is nil again
Inside the scope obj
keeps the object alive and thus wobjc
points to the same object as obj
. But when obj
goes out of scope, the object is released and as that was the only strong reference to it, is deallocated. As a result wobj
becomes nil
.
An unsafe_unretained retain reference is just a pointer to the object that has no knowledge about Obj-C memory management at all. The code
_unsafe_unretained id wobj = nil;
{
__strong id obj = [Object new];
wobj = obj;
// wobj points to the same object as obj
}
// wobj points to the memory address where an object used to be.
// This object has been deallocated! wobj is a dangling pointer!
// Trying to access the object via wobj may crash the app or cause
// other undefined behavior.
is equivalent to
id wobj = nil;
{
id obj = [Object new];
wobj = obj;
[obj release];
}
in a non-ARC environment. wobj
won't be nil
but the object it used to point to has already been dealloced and the memory may not even belong to the process anymore or it may have been recycled to store another object or any kind of allocated data (e.g. using malloc()
).
Usually you want to use weak for references that don't keep the object alive. A typical situation where this is a problem is if object A has a strong references to object B A->B
, and the other way round B->A
. That is a retain cycle and now neither object A nor B will ever get released again, because A keeps B alive and B keeps A alive, and that is still true if nobody else has any reference to either A or B, both objects will always have a retain count of at least one. To fix that, one of both must have a weak reference to the other one.
E.g. if you write a XML parser, then XML nodes will have strong references to all their sub-nodes, to keep those alive and accessible but sub-nodes typically have a reference to their parent node and that would then be a weak node. That way you can get back to the parent node from any sub-node but they don't keep the parent alive, so if nobody else does (neither its parent nor any external reference), the parent node dies and the sub-nodes of it die with it.
Usually the only reason to use unsafe_unretained is performance. First of all, every object has a linked list containing all the address pointers of weak variables pointing to this object, so when the object dies, all these variables can be set to nil
. Managing that linked list consumes time and the list itself consumes memory. Then every weak reference must temporarily become strong to ensure an object won't be released why you call a method on it. And finally, all of this must happen thread-safe, so it will always involve locking, even if your process is single threaded.
__weak id obj = someObject;
[obj performMethod];
obj = nil;
in fact is complex code behind the scenes and roughly equivalent to
lock(memlockOf(someObject));
id obj = someObject;
addWeakRefToLinkList(someObject, &obj);
unlock(memlockOf(someObject));
lock(memlockOf(obj));
id temp = [obj retain];
unlock(memlockOf(obj));
[temp performMethod];
[temp release];
lock(memlockOf(obj));
removeWeakRefFromLinkList(obj, &obj);
obj = nil;
unlock(memlockOf(obj));
And keep in mind that C pointers cannot be weak, so they are always unsafe_unretained. If you do this
id obj = [Object new];
void * cptr = (__bridge void *)obj;
Then cptr
is in fact an unsafe_unretained reference to the object. You can make a C reference "quasi strong" if increase the retain count
id obj = [Object new];
void * cptr = (__bridge_retained void *)obj;
this is equivalent to
id obj = [Object new];
void * cptr = (void *)[obj retain];
in a non-ARC environment. The retain counter is increased by one and thus ARC will never release that object, as even if all ARC references go away, the object has at least a retain counter of one left.
But now the object is never released at all, unless you balance that with transfer bridging:
{
id obj = (__bridge_transfer id)cptr;
// Use obj all you want but don't touch cptr after that!
}
which is equivalent to
{
id obj = (id)cptr;
// Use obj all you want but don't touch cptr after that!
[obj release];
}
in a non-ARC environment. It's important that "transfer" means you are transferring the ownership back to ARC and thus you must not touch the cptr
variable after doing so, as now ARC decides when the object dies and it won't set cptr
to nil
when that happens. Transfer means "make a strong ARC reference out of it but don't do anything with the retain count", so the retain count is not increased but once the strong reference is lost, the retain count is decreased as usual and this balances the extra retain of the retained bridging where the retain count was just increased but nothing else did happen.