Assigning to self in Objective-C

余生颓废 提交于 2019-11-27 00:18:36

问题


I'm from the C++ world so the notion of assigning this makes me shudder:

this = new Object; // Gah!

But in Objective-C there is a similar keyword, self, for which this is perfectly acceptable:

self = [super init]; // wait, what?

A lot of sample Objective-C code uses the above line in init routines. My questions:

1) Why does assignment to self make sense (answers like "because the language allows it" don't count)

2) What happens if I don't assign self in my init routine? Am I putting my instance in some kind of jeopardy?

3) When the following if statement fails, what does it mean and what should I do to recover from it:

- (id) init
{
    self = [super init];

    if (self)
    {
        self.my_foo = 42;
    }

    return self;
}

回答1:


This is a topic that is frequently challenged by newcomers:

  • Wil Shipley: self = [stupid init];
  • Matt Gallagher: What does it mean when you assign [super init] to self?
  • Apple documentation: Implementing Initializers
  • Cocoa-Dev: self = [super init] debate

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.




回答2:


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.




回答3:


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.




回答4:


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.




回答5:


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.




回答6:


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.



来源:https://stackoverflow.com/questions/1341734/assigning-to-self-in-objective-c

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