Assigning to self in Objective-C

戏子无情 提交于 2019-11-28 04:09:10

This is a topic that is frequently challenged by newcomers:

Basically, it stems from the idea that a superclass may have over-ridden the designated initializer to return a different object than the one returned from +alloc. If you didn't assign the return value of super's initializer into self, then you could potentially be dealing with a partially initialized object (because the object that super initialized isn't the same object that you're initializing).

On the whole, it's pretty rare for super to return something different, but it does happen in a couple of cases.

In Objective-C, initializers have the option of returning nil on failure or returning a completely different object than the one the initializer was called on (NSArray always does this, for example). If you don't capture the return value of init, the method might be executing in the context of a deallocated object.

Some people disagree about whether you should do the whole assign-to-self rigamarole if you don't expect to get something else back from the superclass initializer, but it's generally considered to be good defensive coding.

And yes, it looks weird.

It is true that init may return nil, if the initialization fails. But this is not the primary reason why you should assign to self when you implement your own initializers.

It has been mentioned before, but it is needed to stress even harder: the instance returned from an initializer may not be the same instance as the one you sent in, in fact it may not even be of the same class!

Some classes use this as a standard, for example all initializer to NSString and NSArray will always return a new instance of a different class. Initializers to UIColor will frequently return a different instance of a specialized class.

And you yourself can happely implement something like this if you want:

-(id)initWithName:(NSString*)name;
{
  if ([name isEqualToString:@"Elvis"]) {
    [self release];
    self = [[TheKing alloc] init];
  } else if (self = [super init]){
    self.name = name;
  }
  return self;
}

This allows you to break out the implementation of some special case into a separate class, without requiring the clients of your API to care or even know about it.

kperryua

All the other points here are valid, but it's important for you to understand as well that self is an implicit parameter to every Objective-C method (objc_msgSend() passes it) and can be written to, just like any other method parameter. (Writing to explicit parameters is generally frowned upon, unless they are out parameters.)

Typically, this is only done in the -init method, for the reasons others have stated. It only has any effect because self is returned from the method and used in the assignment id obj = [[NSObject alloc] init]; It also affects the implicit resolution of ivars, because, for example, if myVar is an ivar of my class, then accessing it in a method causes it to be implicitly resolved to self->myVar.

I'm still new to Objective C, but this post helped me in understanding this.

To sum it up, most init calls return the same object that self is already initialized to. If there is an error, then init will return nil. Also, some objects such as singletons or unique objects (like NSNumber 0) will return a different object than the one initialized (the singleton or a global 0 object). In these situations you need to have self reference that object. I'm by no means an expert in what is going on behind the scenes here, but it makes sense on the surface, to me.

If [super init] returns nil that means that you have been deallocated and your self parameter is now an invalid pointer. By blindly following the self = [super init] convention you will save you from potentially nasty bugs.

Consider the following non-typical initializer:

- (id)initWithParam:(id)param {
    if (!param) {
        // Bad param.  Abort
        self = [super init]; // What if [super init] returns nil?
        [self release];
        return nil;
    }
    else 
    {
        // initialize with param.
        ...
    }
}

Now what happens if my superclass decides to abort and return nil? I have been de-allocated and my self parameter is now invalid and [self release] will crash. By re-assigning self, I avoid that crash.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!