Well...I have read and have done a lot of research on the expression of [super init] in class inheritance of objective-c. Even some of the questions have been well explained and answered on stackoverflow. However, I still don't really understand how inheritance or the [super init] works.
In other languages, the superclass knows nothing about the subclass. There is no way for the superclass to return an object of the subclass because the superclass has no knowledge of the subclass. So my question is if expression self = [super init] return the object of the SUPERCLASS or SUBCLASS. Here I do know that the [super init] could return another object or nil, which makes sense. But assuming everything works fine and neither is it nil nor return another object. If it returns a regular object, does it return the object of the superclass or derived class, which is the class in which this self = [super init] is defined. If it returns an object of the super class, then it makes sense but then since as we know, the object of the superclass knows nothing about the subclass, how can it access the members (fields, messages or methods) of the subclass. If it returns an object of the subclass, then it does not make sense, since there is no way that the superclass can return an object of the derived class because the superclass knows nothing of it.
This is one of the aspects that is really confusing for those who transition from other languages to objective-C.
self = [super init]
will return the object from the superclass. However, note that the object itself has likely been allocated using alloc on your current class.
Consider the following:
#interface A : NSObject
- (instancetype)init;
#end
#interface B : A
- (instancetype)init;
#end
#implementation B
- (instancetype)init {
self = [super init];
if (self) {
// Do initialization for B
}
return self;
}
#end
When you create a new object of a class B you do as follows:
B *obj = [[B alloc] init];
In turn the following happens:
[B alloc]allocates the object with enough space to hold all of B.
Calls init on the newly created object of class B.
Then init on class A is called from B's init method
init on class A will* return the object allocated with B's alloc.
*) Note that the init method may return another object than the allocated one. This is allowed, and is a reason why you usually should assign the result to self.
Read more - What does it mean when you assign [super init] to self?
Related
If I have an NSObject subclass which either has no -init method or simply does nothing in -init, is there any difference between an instance created these two ways:
MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];
By "does nothing in -init" I mean
- (id)init {
self = [super init];
if (self) {
}
return self;
}
Since NSObject's -init method itself does nothing, I can't see there being any difference, but of course the advice is that you must call -init to properly prepare an object.
Here's the snippet from NSObject's -init method which got me wondering about this:
The init method defined in the NSObject class does no initialization; it simply returns self.
If I have an NSObject subclass which either has no -init method or
simply does nothing in -init, is there any difference between an
instance created these two ways:
MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];
Technically, there is no difference.
But that doesn't mean you should use a bare +alloc to ever create an instance for a variety of reasons.
First, it is the principal of the thing. Objective-C coding standards say +alloc should always be followed by -init.
Secondly, it is all about consistency and code maintenance. What happens when you refactor MyClass to be a subclass of some class where the designated initializer is actually critical? A nasty, hard to figure out, bug is what happens.
Of relevance, note that the use of +new has been all but deprecated for a similar reason. It makes refactoring tedious (dammit! gotta break apart THIS call site, too!) and the convenience factor is exceedingly minimal.
No, it's not and you're not doing nothing, you're calling [super init] and that does a lot to initialize your superclasses up until NSObject.
You can do it in theory.
When you want to create an instance, you can do it simply using the alloc method, so this code is perfectly accepted:
NSObject *someObject = [NSObject alloc];
What creates the instance is the alloc method, so you have created an instance of NSObject.
But if you want to use it you have to initialize it, since the NSObject init method is used by a class to make sure its properties have suitable initial values at creation (Apple documentation).
The most important thing done by the init method is to create the self variable, so if you want to use the instance created with the alloc method, you have to init it.
- (id)init {
self = [super init];
if (self) {
// initialize instance variables here
}
return self;
}
Without the initialization method you have only an unusable instance.
alloc allocates a place in memory for the instance of the object to be stored. If you’re using a local variable it is allocated on the stack, while objects (ivars etc) are allocated on the heap.
init initialises the instance of the object and points it to the allocated memory space - this is why you must always call init after alloc.
e.g.
MyClass *instance = [[MyClass alloc] init];
In your instance your init implementation is empty so it can be removed and you can let the superclass handle it. You would override init to set some state on the object itself.
You might want to take some time to read the Apple Documentation on this if you want to brush up.
Calling MyClass *instance = [MyClass alloc]; - will leave you with an invalid object. You need to allocate and initialize every object you create.
If you do it this way, all objects until MYClass will be initialised. MyClass won't though.
I am from Actionscript Background. In Actionscript Class Method can access only Class Methods and Class properties.
But In Objective C,
How Class method gameResultAll can access Instance Method initFromPlist
+(NSMutableArray *)gameResultAll://Class Method
-(id)initFromPlist:(id)plist;//Instance Method
NSMutableArray *gameResults = [GameResult gameResultAll]; // (returns GameResult array)
Why [self init] method is called instead of [super init] to create an instance from class method.
Thanks in advance.
#import "GameResult.h"
#implementation GameResult
#define GAME_RESULT_KEY #"gameresult_key"
#define SCORE_KEY #"score"
+(NSMutableArray *)gameResultAll
{
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
for (id plist in [[[[NSUserDefaults standardUserDefaults] dictionaryForKey:GAME_RESULT_KEY] mutableCopy] allValues])
{
GameResult *gameResult = [[GameResult alloc] initFromPlist:plist];
[resultArray addObject:gameResult];
}
return resultArray;
}
//Designated initialiser
-(id)initFromPlist:(id)plist
{
self = [self init];
if(self)
{
if([plist isKindOfClass:[NSDictionary class]])
{
NSDictionary *resultDictionary = (NSDictionary*)plist;
_score = (int)resultDictionary[SCORE_KEY];
}
}
return self;
}
You asked:
How Class method gameResultAll can access Instance Method initFromPlist
It can access that method because you used the alloc method, which creates an instance of GameResult. Now that you have an instance, you can use instance methods in conjunction with this instance.
By the way, this is a very common pattern, a "convenience" class method that allocates an instance of an object (with alloc) and initializes the object (with init or some permutation of that). Or, as in this case, it can create an array of these objects.
You then go on to ask:
Why [self init] method is called instead of [super init] to create an instance from class method.
I can understand the confusion, but there is an important, yet subtle distinction in the behavior of these two.
Imagine this scenario:
At some future date, you subclass GameResult, e.g. ArcadeGameResult;
You implemented an init method for ArcadeGameResult that initializes some properties unique to this subclass; and
You happen to initialize a ArcadeGameResult instance like so:
ArcadeGameResult *agr = [[ArcadeGameResult alloc] initFromPlist:plist];
Because the initFromPlist uses [self init], it means that the the initFromPlist method of GameResult will end up calling the init method of the object (which in this example, is actually a ArcadeGameResult object). But if initFromPlist in GameResult called [super init] instead, it would not have called ArcadeGameResult's init method and thus initFromPlist would be problematic if ever used in conjunction with a subclass.
Bottom line, unless the method you're calling is the exact same method signature, it's safer to call the self rendition rather than the super rendition. It's a little more flexible in case you ever decide to subclass in the future.
There is a corollary to the counsel. When calling class methods from an instance method, you should refer to [self class] rather than the class name. So, imagine your GameResult class had a class method:
+ (void)someClassMethod
{
// do something
}
If you had some GameResult instance method that was going to avail itself of this method, you might be tempted to write:
- (void)someInstanceMethod
{
// do some stuff
[GameResult someClassMethod];
}
But that's not a good idea. You would instead use the following:
- (void)someInstanceMethod
{
// do some stuff
[[self class] someClassMethod];
}
They look very similar, but the latter lets you implement a someClassMethod in a subclass, and this instance method will still work. If you use the former construct, the subclassed class method wouldn't be called by someInstanceMethod.
These are subtle issues, and probably not critical for your current code sample. But hopefully it illuminates the choice of [self init] versus [super init] in this situation.
In Actionscript Class Method can access only Class Methods and Class properties.
That's not different in Objective-C either (because nothing else would make sense), so:
How Class method GameResultAll can access Instance Method initFromPlist
Only through a valid instance.
Why [self init] method is called instead of [self super] to create an instance from class method.
Because the latter is a syntax error, perhaps? Read a basic Objective-C tutorial.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
why does initializing subclasses require calling the super class's same init function?
I really can't understand the role of super in initializing an object.
For example, having this (example — not written by me) code:
#implementation MyObject
- (id) init
{
if([super init]){
return self;
} else {
return nil;
}
}
#end
What [super init] actually does? I'm confused, can't get the point
It is necessary to ensure correct initialisation of inherited instance variables from the super class of MyObject.
Since Objective-C is object oriented you can inherit from other classes. When you inherit from other classes you can intercept messages and get to decide if you pass them on to the class you inherit from. In the case of init it is almost always important to do self = [super init] or use the designated init method of the class to make sure the object is created correctly. Imagine if in MyObject in your init method you create an NSMutableArray that your class uses but init was never called because someone else inherited from your class and never called [super init]. You would then have nil references or either a bad pointer every where you attempted to used your NSMutableArray. The reason why it is important to set self equal to [super init] is the value of self may change such as in error recovery.
//this is valid
-(id)init
{
if((self = [super init]))
{
if(someInitializationFails)
{
[self release];
self = nil;
}
}
return self;
}
Wil Shipley recommends this (from 2009):
- (id)init;
{
if (!(self = [super init]))
return nil;
// other stuff
return self;
}
But why assign super init's return to self?
Matt Gallagher's article attempts to explain it...
-- Quote:
If you remember back at the start, I
said that the initWithString: part of
a typical [[MyClass alloc]
initWithString:#"someString"]
invocation is converted into an
objc_msgSend call:
MyClass *myObject2 = objc_msgSend(myObject1, initSelector, #"someString");
So by the time we get
to the inside of the method, self
already has a value; its value is
myObject1 (i.e. the allocated object,
as returned from the [MyClass alloc]
call. This is essential because
without it, the super invocation
wouldn't be possible — the self value
is used by the compiler to send the
invocation:
[super init];
becomes:
objc_msgSendSuper(self, #selector(init));
Yes, self already
has a value when your initializer
starts. In fact, it is almost
guaranteed to be the correct, final
value.
-- Unquote
Essentially, I think a lot of people are left confused as to what each init method's 'self' is pointing to exactly, up through the superclass chain.
The answer to this riddle is implied in Apple's Objective-C Programming Language doc, under the section titled Designated Initializers:
Note that B version of init sends a
message to self to invoke the
initWithName: method. Therefore, when
the receiver is an instance of the B
class, it invokes the B version of
initWithName:, and when the receiver
is an instance of the C class, it
invokes the C version.
Or, in other words, the 'self' variable points to the our instance that is being initialized. Again to reemphasize, all of these init methods up through the superclass chain are inherited by our instance, and as such, the 'self' variable in them points to our instance (unless explicitly changed) .
Am I right? Of course!
Disclaimer, I'm new to Objective C. But I can't find this explained. I've seen two ways of implementing init:
- (id)init {
if ([super init]) {
return self;
} else {
return nil;
}
}
and
- (id)init {
if (self = [super init]) {
// do your init business here
}
return self;
}
so let's say i have:
myObj = [[MyObject alloc] init];
where MyObject class is a subclass of NSObject. in the second example, does init not return an initialized version of NSObject? so myObj would ... how would it know what it is? wouldn't it think it was an NSObject rather than a MyObject?
1) First version is just wrong. self should be always assigned with value returned by super initializer, because init<...> of super can return another object upon initialization (it's not unusual BTW). Second version is actually an 'official' way to implement init<...> methods.
2) 'wouldn't it think it was an NSObject rather than a MyObject'. myObj is instance of 'NSObject' and instance of 'MyObject'. It's the whole point of inheritance.
i just want to know, under the hood, how it does it.
It's pretty simple. 99.9% of all the classes you'll ever write will inherit from NSObject in some fashion. In the initializers, you're supposed to invoke super's designated initializer and assign it to self. Eventually, [super init] will be invoking -[NSObject init]. According to the documentation, that's implemented like this:
- (id)init {
return self;
}
So technically, if you inherit directly from NSObject, you're probably safe to not do the assignation of self = [super init];, because you know (and you're guaranteed) that this is equivalent to: self = self;, which is kind of pointless. Regardless, you should leave it in for consistency's sake.
However, once you start getting further down the inheritance chain, and especially when you're inheriting from opaque classes (ie, a class whose .m file you do not have), then things start getting shady. It is possible that you'll come across a class whose designated initializer looks something like this:
- (id) initWithFoo:(id)aFoo {
if ([aFoo isSuperFast]) {
[self release];
return [[SuperFastFooWrapper alloc] initWithFoo:aFoo];
}
self = [super init];
if (self) {
_foo = [aFoo retain];
}
}
This isn't as common, but it does happen. In this case, we're destroying self ([self release], to balance the alloc call that immediately preceded this) and instead returning a different object.
I have read many posts about this now but I do not still understand it. I would appriciate an answer rather than a link because I probably already have read it.
if (self = [super init]) {
}
return self;
When I am calling the [super init] I know I am calling the method on "self"(the objects address) but I am starting the "method-search" in the superclass. When this returns I assign the object type id to self...This is where I am getting lost.
Am I assigning "self" as an initialized object up to the point of the superclass to self..?
I understand that I am doing this check to stop the initializing if the superclass implementation of the initializer returns nil however I dont understand what I am assinging to self....I thought self was an address to the current object in memory.
Thanks in advance
The assignment has always seemed a bit hacky to me. Its main point is that the superclass might want to return some other instance than the one that was initially allocated:
id foo = [[Foo alloc] init];
#interface Foo : SuperFoo {…}
#implementation Foo
- (id) init
{
self = [super init];
if (!self)
…;
return self;
}
#interface SuperFoo : NSObject {…}
#implementation SuperFoo
- (id) init
{
[self release];
return [OtherClass alloc];
}
This is crazy indeed, but the fact is that [super init] might return an object different from the previous self. See Mike Ash’s blog post, that should make things super clear.
There are two reasons, why that assignment is important:
The designated initializer (di) of the superclass may return nil if initialization fails.
In this case, without the assignment of its return value to self, you would end up in a state that is completely unsafe — most likely, your superclass's di will have released the object pointed at by self in order to not leak memory.
If you went on using that instance and you're lucky you should see a crash in the not so distant future. If you're not that lucky, you're going to mess with some other object's internal state and lose or corrupt user-data before your program crashes.
There are quite a few classes in Cocoa(Touch) — the class-clusters like NSString and NSArray probably being the most prominent examples — that may return a different instance from their di.
The pointer you will receive from [NSString alloc] for example will almost definitely not be the same you'll obtain from a subsequent call to initWithFormat:#"Hello %#!", #"foo".
lets break this into smaller chunks:
1- when your calling [super init] your making your super class run its init function first so it can initialize your object that your inheriting, normally that would be NSObject or any superclass that you decided to extend.
the super init functions will return self at the end of that process, just like your doing in your init function
2- when you do the assignment: self = [super init] your actually assigning that return value from your super into your own.
3- the if around that assignments actually evaluates the success/failure of the super init call, cause if it failed you would have got a nil back and the assignments would have been nil to self. so evaluating nil will return false and you wont run your init code.
4- eventually you also return self (nil if failed / actuall object if it succeeded)
hope that clears it.