Why check self! = Nil in -init when a nil message has no effect?

Assuming our -init method -init calls messages on self , why is it usually checked if self != nil , if nil messaging has no effect?

Let's say we have an initializer as follows:

 - (id)init { self = [super init]; if (self) { [self doThis]; [self setFoo:@"Bar"]; } return self; } 

Instead of checking self we could write:

 - (id)init { self = [super init]; [self doThis]; [self setFoo:@"Bar"]; return self; } 

Now, if for some reason [super init] returns nil , as far as I know, there would be no difference in the results of the method. Why are we constantly doing this check?

+6
source share
2 answers

You can send a message to nil, but you cannot access nil instance variables. You will get an EXC_BAD_ACCESS exception.

Consider a class with instance variables:

 @implementation MyObject { int instanceVariable; } - (id)init { self = [super init]; instanceVariable = 7; return self; } 

What happens if [super init] returns nil in this example? You will try to access this instanceVariable value of a null pointer, and you will get an exception.

Even if you do not get access to any instance variables, other things may go wrong if you do not check self == nil . You can easily test malloc allocated memory or file descriptors, or pass yourself to some method that does not expect a null value.

Other answers claim that you can leak objects if you don't check for null. For instance:

 @implementation MyObject @synthesize someProperty; // assume it an NSObject * - (id)init { self = [super init]; [self setSomeProperty:[[NSObject alloc] init]]; return self; } 

This will not occur under ARC, even if self is zero. In manual reference counting (MRC), this example will flow if self is zero or not, because there is nothing to balance the saving score of +1 from [NSObject alloc] .

The correct way to do this in MRC is:

 - (id)init { self = [super init]; [self setSomeProperty:[[[NSObject alloc] init] autorelease]]; } 

or that:

 - (id)init { self = [super init]; NSObject *object = [[NSObject alloc] init]; [self setSomeProperty:object]; [object release]; return self; } 

None of them will leak out, regardless of whether it is self or not.

If you bypass the setter method, like this, you just crash if self is nil:

 - (id)init { self = [super init]; _someProperty = [[NSObject alloc] init]; return self; } 
+7
source

If [super init], in turn, returns nil, then you may select more objects that will never be used, since when you return yourself, you will return nil; Therefore, these objects will not be released.

0
source

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


All Articles