Why does Objective-C make placement and init in separate statements so that the object is released in accordance with the Xcode parser?

I take the first steps with Objective-C and run into a minor, albeit confusing problem, with the static analyzer (Product-> Analyze) in Xcode 4.1. I created a simple fraction class for rational numbers that I select and initialize, for example,

Fraction* f = [[[ Fraction alloc ] initWithNumerator:3 withDenomimator:5] autorelease]; [ f print ]; 

where print is a method that just uses NSLog to display a fraction, everything works fine. However, if I divided the alloc / init construct into two statements (I understand that this is not idiomatic - I'm just trying to understand the mechanism) and use the release manual, not autorelease , giving:

 Fraction* f = [ Fraction alloc ]; // 1. Method returns an Objective-C object with // a +1 retain count (owning reference) [ f initWithNumerator:3 withDenomimator:5]; // 2. Object released [ f print ]; // 3. Reference-counted object is used after it is released [ f release ]; 

the program still works without errors, but the Xcode analyzer gives warnings in the comments. Why does Xcode think that calling init causes the object to be freed?

Thinking about this, when I ask a question, I see that my two programs are not completely equivalent, because in the first fragment my pointer f is the result of calling init , while in the second fragment it is the result of alloc . Therefore, changing your code to

  Fraction* a = [ Fraction alloc ]; Fraction* f = [ a initWithNumerator:3 withDenomimator:5]; [ f print ]; [ f release ]; // or should it be [ a release ] ? 

makes it exactly equivalent, and the static analyzer stops complaining. Is it possible that init can return a different pointer than the one that was passed to it from alloc , and not just configure the memory in which it was passed? With this code, should you map [ a release ] to alloc or [ f release ] to init ?

+4
source share
3 answers

So, is it possible that init can return a different pointer than the one that was passed to it from alloc, and not just configure the memory that it passed?

absolutely.

With this code, should I match [release] with alloc or [f release] with init?

you assigned the value of the initialized object f (like you). at the moment a may be a dangling pointer (if another address is returned). there, f should be release d.

the explanation for this order is that the object may have decided to return the specialized version / variant on its own, and this redistribution occurs along the init... chain.

stupid demonstration:

 @interface Fraction : NSObject { @private int numerator; int denominator; } @end static Fraction* EvilFraction = ...; @implementation Fraction - (id)initWithNumerator:(int)num denominator:(int)den { self = [super init]; if (nil != self) { if (0 == den){ [self release]; return [EvilFraction retain]; } } return self; } @end 
+5
source

Attempting to split calls into +alloc and -init explicitly forbidden by Apple according to the documentation for +[NSObject alloc] :

To complete the initialization process, you must use the init method .... For example:

TheClass * newObject = [[TheClass alloc] init];

and -[NSObject init] :

In some cases, the init method may free a new object and return a placeholder. Therefore, programs should always use the returned object on initialization, and not necessarily on the return using alloc or allocWithZone :, in the following code.

The static analyzer complains because it expects +alloc be paired with -init . Since -init can free the sender, the static analyzer therefore assumes that you are trying to call a method on a freed instance.

+2
source

So, is it possible that init can return a different pointer than the one that was passed to it from alloc , and not just configure the memory in which it was passed?

Yes, that's for sure. This is also the reason why you do not just call [super init] in your initializers; instead, you call it and assign the result to self , because you will not necessarily return the same instance.

Related documentation is in the Objective-C Programming Language .

With this code, should I pair [ a release ] with alloc or [ f release ] with init ?

If you really want to do something like this, you will need to check that they are not equal in the first place, otherwise you would be reissued. But the real solution is to not separate alloc and init . The fact that the idiomatic way of creating objects in Objective-C and using it differently, that you have to add extra code, is counterproductive.

+2
source

Source: https://habr.com/ru/post/913986/


All Articles