Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I call self=[super init]

Tags:

objective-c

Let's say I create my class and its init method. Why should I call and return value of superclass init assigned to self? Which cases it covers?

I would appreciate examples why would I need it for Cocoa superclass and non-Cocoa.

like image 1000
Pablo Avatar asked Jun 02 '10 10:06

Pablo


People also ask

Why self super init?

Why do we assign [super init] to self here? The textbook reason is because [super init] is permitted to do one of three things: Return its own receiver (the self pointer doesn't change) with inherited instance values initialized. Return a different object with inherited instance values initialized.

What does super()__ init__ do?

When you initialize a child class in Python, you can call the super(). __init__() method. This initializes the parent class object into the child class. In addition to this, you can add child-specific information to the child object as well.

Is super init necessary?

In general it is necessary. And it's often necessary for it to be the first call in your init. It first calls the init function of the parent class ( dict ).

Why we use super init in Swift?

This is called class inheritance or subclassing, the class you inherit from is called the “parent” or “super” class, and the new class is called the “child” class. For safety reasons, Swift always makes you call super. init() from child classes – just in case the parent class does some important work when it's created.


4 Answers

You mean why

self = [super init];

rather than

[super init];

Two reasons:

  1. in initialisation, failure is indicated by returning nil. You need to know if initialisation of the super object failed.
  2. the super class might choose to replace the self returned by +alloc with a different object. This is rare but happens most frequently with class clusters.

Edited in response to Michael's comment:

I can understand why I need to save and return [super init]. But is it just convention and good looking makes us use self as a temporary variable to pass result along?

No. Instance variables are accessed relative to the self pointer, so in the following:

-(id) init
{
    self = [super init];
    if (self != nil)
    {
        myBoolIvar = YES; 
       // The above is an implicit version of self->myBoolIvar = YES;
    }
    return self;
}

self has clearly got to point to the right block of memory i.e. the one you are going to return.

The other point is that if super init returns different class instance then the rest of the code after that line may not even make sense, lead to memory leaks and crashes, not even talking about the object instantiated from that class.

That could be a problem. If I subclassed NSNumber and [super init] decided to return an NSString (which it could - there's nothing to stop it) that would clearly be a disaster. Whatever super returns from -init must be "compatible" with the subclass in the sense of providing space for ivars and being further subclassible or it's a horrendous bug (unless, of course, the problem is documented). So, in general, you don't need to worry about checking the class. However, do read the documentation. See for instance the section on subclassing NSString in NSString's docs.

like image 87
JeremyP Avatar answered Sep 20 '22 12:09

JeremyP


I know it is a little bit late for my answer, but I cannot stop myself from posting a link which I found very useful in clearing my doubt about this problem.

Matt Gallagher: What does it mean when you assign [super init] to self?

EDIT: As per the comments, here are the essential points in the link

To understand why self=[super init]; we need to consider many points. Let's tackle it one by one.

What is self

Every method has two hidden parameters: self and _cmd. So the method call

- (id)initWithString:(NSString *)aString

is changed by compiler into a function call like this

id initWithString(id self, SEL _cmd, NSString *aString);

Why do we need self?

The reality is that the compiler uses the self parameter to resolve any reference to an instance variable inside a method.

Suppose that we have a method setValueToZero and value is an instance variable of the class it belongs to, then the implementation

- (void)setValueToZero
{
    value = 0;
}

will be converted by the compiler into a function like this

void setValueToZero(id self, SEL _cmd)
{
    self->value = 0;
}

Do self already have a value when init is called?

Following is an example of a typical object creation and initialization.

[[MyClass alloc] initWithString:@"someString"]

Here, by the time we get into the initWithString method, self will have the newly allocated object as its value (i.e., the return value from [MyClass alloc]). In fact, it is almost guaranteed to be the correct, final value.

Why self = [super init];?

It is because [super init] is permitted to do one of the three things:

  1. Return its own receiver (the self pointer doesn't change) with inherited instance values initialized.
  2. Return a different object with inherited instance values initialized.
  3. Return nil, indicating failure.

In the first case, assignment has no effect on self. In the third case, the initialization has failed, self is set to nil and it is returned.

The reason behind assignment to self is with the second case. Consider the following

- (id)initWithString:(NSString *)aString
{
    self = [super init];
    if (self)
    {
        instanceString = [aString retain];
    }
    return self;
}

We want the conversion from

instanceString = [aString retain];

to

self->instanceString = [aString retain];

to act on the correct value and thus we have to change the value of self.

When would [super init] return a different object?

In one of the following situations

  1. Singleton object (always returns the singleton instead of any subsequent allocation)
  2. Other unique objects ([NSNumber numberWithInteger:0] always returns the global "zero" object)
  3. Class clusters substitute private subclasses when you initialize an instance of the superclass.
  4. Classes which choose to reallocate the same (or compatible) class based on parameters passed into the initializer.

In all but the final case, continuing to initialize the returned object if it changes is a mistake — the returned object is already completely initialized and isn't necessary related to your class anymore. So a better init approach will be as follows

- (id)initWithString:(NSString *)aString
{
    id result = [super init];
    if (self == result)
    {
        instanceString = [aString retain];
    }
    return result;
}

Conclusion

You don't need to assign [super init] to self to make most classes work. In some obscure cases, it is actually the wrong thing to do.

So why do we continue to assign to self? It's the traditional template for an initializer, and although it's wrong in some cases, it is right in other cases which have been written to expect this approach.

like image 25
Jomoos Avatar answered Sep 21 '22 12:09

Jomoos


Basically every Objective-C class is a subclass. It's either some class you've specified or NSObject.

In the subclass (your class that you're working on) you call self = [super init]

What this basically does is calls the super class's (the ones I mentioned above) init method (the constructor) and assigns it to the current class.

This makes sure that the superclasses' initializing method is called.

Now for If(self) This basically checks if the above piece of code worked.

This is done to insure that if you call some Instance Variable of the super class, you'll be able to do so.

like image 4
Venu Gopal Tewari Avatar answered Sep 23 '22 12:09

Venu Gopal Tewari


In most cases, setting self to [super init] does nothing since [super init] will wind up returning self anyway. There are some rare cases, however, where [super init] will return something different. It may return nil if it fails to initialize the superclass for some reason or it may decide to return a completely different object.

like image 1
Ferruccio Avatar answered Sep 20 '22 12:09

Ferruccio