Why should I call self=[super init]

2020-01-24 03:58发布

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.

标签: objective-c
6条回答
Root(大扎)
2楼-- · 2020-01-24 04:05

Source


Implementing The Designated Initializer

**

self

** Inside a method, self is an implicit local variable. There is no need to declare it, and it is automatically set to point to the object that was sent the message. (Something like this in Android programming.) Typically, self is used that an object can send a message to itself. Example here:

 return self;  

**

super

** When we overriding a method, we want to keep what method of the superclass is doing and have your subclass add something new on that. To make it easier, there is compiler directive in Objective-C called super. How does super work? Usually when you send a message to an object, the search for a method of that name starts in the object's class. If there is no such method, the search continues in the superclass of the object. The search will continue up the inheritance hierarchy until a suitable method is found. (If it gets to the top of the hierarchy and no method is found, an exception is thrown). When we send a message to super, we are sending message to self, but the search for the method skips the object's class and start at the superclass. In the above case, we send init message to super. This calls NSObject's init method.

查看更多
乱世女痞
3楼-- · 2020-01-24 04:15

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.

查看更多
Ridiculous、
4楼-- · 2020-01-24 04:16

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.

查看更多
贪生不怕死
5楼-- · 2020-01-24 04:25

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.

查看更多
啃猪蹄的小仙女
6楼-- · 2020-01-24 04:25

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.

查看更多
家丑人穷心不美
7楼-- · 2020-01-24 04:26

Because you have to initialize the object somehow, and presumably you want to do any initialization a superclass required be done, since you're descending from it.

查看更多
登录 后发表回答