Why shouldn't it be that way? Calls to -init
are meant to return a given object with a +1 retain count, and doing a "temporary retain" is the safest way of guaranteeing that self remains alive throughout the entirety of a given init method. Consider what happens if we peel back the layer of Objective-C abstraction and turn -init
into the function pointer it's IMP resolves to:
id init(id self, SEL _cmd) {
//+0 self given requires explicit retain to guarantee lifetime
//...
//(if retained) +1 self is returned; (if not retained) +0 self is deallocated
}
If given a self
with a +0 retain count (as is common in most methods that retain their arguments i.e. setters), then you would have to guarantee that somewhere up the inheritance chain someone was nice enough to retain self away from whatever happened to allocate it (ending in self
having a rather ambiguous retain count of +1). But, if you receive a self with a +1 retain count, and you do a retain-release it yourself,you can be certain that it remains alive through your -init
method, and that you and you alone have ownership of self
. And if the given self was not "alive", then you're guaranteed to return nil rather than an object in the middle of deallocation. Thus, the above becomes (in pseudo-C):
id init(__attribute((ns_consumed))id self, SEL _cmd) {
//implicit retain of +1 self returns self with +2
//...
//implicit release of +2 self returns self with +1
}
I like to call this pattern "old-school atomic access", and it's used in Apple frameworks designed before @synchronized {}
atomic getters were invented. When you use a getter backed with a public iVar. You'll often see methods that follow that pattern written like:
- (NSView *)view {
//explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil.
return [[_view retain]autorelease];
}
But all of this doesn't touch the ownership rules of the exception that is -init
and family. -init
methods return objects +1, but who exactly owns them? Well, the allocator* still has a hand in the reference to the variable, and self = [super init]
doesn't actually retain anything (and it also has to obey the whole "returns +1" rule). Well, again I have to turn to pseudo-code, but this time it'll be in Objective-C:
- (id)init {
//self is +1 because -init must return +1
self = [super init];
//implicit [self retain]; leaves self with a +2 reference count
//...
//implicit [self autorelease]; leaves self with a +1 reference count
return self;
}
OK, so now you've got a +1 object floating around claimed by the allocator, so how do you "claim" it? Assignment, of course! The point of implicitly __strong
locals and __strong
properties is to reclaim the object from the allocator entity.
- (void)f {
//Freestanding +1 variable is not owned by the caller, will be deallocated when the method
//passes out of scope.
[[NSObject alloc]init];
//Implicitly __strong local captures reference away from allocator entity,
//which "autoreleases" it's ownership
//We now "own" the returned object.
NSObject *obj = [[NSObject alloc]init];
//Strong property captures reference away from local, saves the object from being deallocated
//when the method passes out of scope
self.object = obj;
}
*Allocator, in the context of this answer, refers to the functions that eventually call malloc()
to allocate space for the object.