In ARC, why does self use the consumed parameter in init methods?

I want to understand ARC, and I read this:

http://clang.llvm.org/docs/AutomaticReferenceCounting.html#consumed-parameters

It says that the consumed parameter is saved until the call and freed at the end of the function (inside the body of the function). He then says that the init... methods init... effectively marked with ns_consumes_self . I do not see the point.

 Foo *foo = [[Foo alloc] initWithWhatever: x]; 

So, alloc returns an object with a hold value of 1, right? Now it is saved again before going into init , and then released at the end of init , so we went back to 1. Why is it created like this? When I think about what a typical init looks like, I get more confused.

 self = [super init]; if (self) { ... } return self; 
+7
source share
2 answers

So alloc returns an object with a hold value of 1, right? Now this is saved again before entering init, and then freed at the end of init, so we went back to 1. Why is it created like this?

Probably because initializers can return a pointer to a different object than the one that self points to. The -init method can say: I do not like this object, I think I will substitute another, and that’s fine. Prior to ARC, such an initializer explicitly issued self (although it did not save it), and then assigned it a different pointer. Presumably, the ns_consumes_self directive ns_consumes_self take care of releasing the object that was passed to the initializer, even if self changed to point to some other object inside the method.

When I think about what a typical init looks like, I get more confused.

It’s good that the behavior should cover cases that are not like the typical -init method. Changing self not typical, it is valid.

+8
source

Why not? The -init calls -init designed to return a given object while storing the number +1, and performing a “temporary save” is the safest way to ensure that the “I” remains alive throughout this initialization method. Think about what happens if we clear the Objective-C abstraction layer and turn -init into a function pointer that IMP allows:

 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 you set a self with a save count of +0 (as is usually the case with most methods that save their arguments, i.e. setters), then you will need to ensure that somewhere in the inheritance chain someone was good enough, to keep yourself away from what happened, to highlight it (ending in self , having a rather ambiguous value of saving +1). But, if you get an “I” with a save factor of +1, and you yourself save it, you can be sure that it remains alive using your -init method and that you and only you own self . And if the given "I" was not "alive", then you are guaranteed to return zero, and not an object in the middle of liberation. So 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 template “old-school atomic access”, and it was used on Apple infrastructures developed before the @synchronized {} atomic getters were created. When you use a getter supported by public iVar. You will often see methods that follow this pattern, written as follows:

 - (NSView *)view { //explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil. return [[_view retain]autorelease]; } 

But all this does not affect ownership rules with the exception of -init and family. -init methods return +1 objects, but who exactly owns them? Well, the allocator * still has a hand in the reference to the variable, and self = [super init] actually saves nothing (and it also has to obey the "returns +1" rule). Well, again I have to go to the pseudo-code, but this time it will 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 have a +1 object floating around declared by the distributor, since you "declare" it? Appointment of course! The point of implicitly __strong locals and __strong properties is to restore an object from a distribution object.

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

* The allocator, in the context of this answer, refers to functions that ultimately call malloc() to allocate space for the object.

+3
source

All Articles