When I have code like the following:
self = [super init]
does self point to super? If so, why would you want this? if my instance object has the variable "someVal", I won't be able to get to it by doing [self someVal]. correct?
How then would I get to the instance variable's using self when self points to super?
does self point to super?
It's really the other way around. super is really the same as self, except that it tells the compiler to start looking for method implementations starting with the superclass rather than the class itself. You can check this by logging the value of super and the value of self; you'll find that they both point to the same address.
When you create an object, you do this:
Foo *f = [[Foo alloc] init];
The alloc allocates the memory that will become the object you're creating, but until that memory is initialized it's just a chunk of memory -- not a valid object. If Foo is a subclass of Bar and Bar is a subclass of NSObject, then by convention Foo's initializer will call Bar's, and Bar's will call NSObject's, so that the initialization proceeds in order: first the memory is initialized by NSObjects' -init, and Bar's init receives the returned value and assigns it to self. It then proceeds to do any Bar-specific initialization, and returns self. Foo's -init then assigns the returned value to self again and finally does any Foo-specific initialization.
All that assigning to self might seem both redundant and confusing. It's really just a convention, but the purpose is to allow the superclass's initializer to return some object other than the one that was allocated, including nil. So, for example, if the initialization of Bar failed for some reason, -[Bar init] could return nil. The possibility that nil might be returned from [super init] is the reason we put the self = [super init] assignment inside a conditional: if the assigned value is nil, the initialization part is skipped and nil is returned. It's also possible that -[Bar init] could return a pointer to an object other than the one that was allocated, such as when an object similar to the one being created already exists and can be reused.
Most of the time, the pointer you get back from -init will be the same one that you got from +alloc, so you could write this:
Foo *f = [Foo alloc];
[f init];
If you write that, however, you're making an assumption that the initializers of your class and all the classes that it inherits from will always return the same object, and will never return nil. By doing that you're breaking the convention and severely hamstringing yourself and whoever wrote the classes from which Foo inherits -- they'll break your code if they return a different object in a future release of the class. Also, it'll look like you don't know what you're doing.
does self point to super?
This question doesn't make sense in an instance method, since there super is not really a concrete/actual pointer-to-instance, it just indicates that the implementation of the superclass must be called. And since in the case of most objects (except class clusters) all methods return self;, then the answer is no: the actual pointer to the instance doesn't change magically by itself.
For the record: the exception is manifested by class clusters (most Cocoa container classes, for example, NSString, NSArray, etc.). These classes often have an initializer method that returns a different instance than the one that was originally allocated, and of which the class is a concrete subclass of the class of the original self. For example, an implementation of the NSString initializer could be:
#implementation NSString
- (NSString *)init
{
[self release];
self = [[__NSCFString alloc] init];
return self;
}
#end
The reason for this is that optimizing for different types of initialization can be achieved this way.
Self is always pointing to one instance. When you use super you are referencing parent methods not a parent instance.
self means current class' instance.
self = [super init] means self is getting the value returned by [super init].
Related
I would like to set a member variable in a derived object before i call [super init].
All I can find is that you should not do such a thing. My worakround, to do it anyhow, works, but actually I like to know what the consequences are when bending the rules. Or even better if there is a correct way to deal with this.
The Details:
I have several wrappers that bind a c++ object to an objective-c objec (mostly UI...View or UI...Controller)
#interface my_scrollview : UIScrollView
{
my_c_class* m_p;
}
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap;
-(void) setContentOffset:(CGPoint)contentOffset;
#end
#implementation dwin_scrollview_ios
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap
{
m_p = pWrap; // illegal but works?
return [super initWithFrame: frame];
//m_p = pWrap; // to late because [super init...] already called overriden func.
}
In my overwritten setContentOffset-method I need to access my C++-Object.
The Problem arises because the initWithFrame internally initializes its content using setContentOffset. So this method is called before I could "legaly" set up the link to my c++-object.
I can implement my overrides with a check if m_p is set(luckily it's initialized to nil). But I have to synchronize the state of the view and my c++-object after the the init-method. In this example this is no big deal but other such realtions are much more complicated and I end up with lot of code that repeats steps of the initialization or otherwise brings me back in sync, although before the [super init...] I know I was in sync.
Is there a pattern to solve this correct (and elegant)?
Is it really so bad to int the pointer before the call to [super init..];?
(I assume one consequence is that this crashes if [super init] returns nil...? any other cases?)
Thanks in advance
Moritz
There is nothing magical about init methods in Objective-C. alloc returns an object of the class that you want, with all instance variables initialized to 0 / nil / NULL / 0.0 etc. Each init method then just executes the code that the developer has written.
There are things that are obviously stupid, like setting an instance variable of the superclass, then calling [super init] which promptly overwrites it. And you need to be aware that init doesn't necessarily return self, but a different object, in which case everything you've initialised in the base class before calling [super init] will be gone.
// illegal but works?
No, it's not illegal. It's perfectly legitimate, although unconventional, to do stuff to an object before its superclass' initializer has been run. It may still lead to unexpected behavior and bugs, but it's not illegal per se. Sometimes it's even necessary, for example when you want to perform some computation and delegate the result of that computation to the superclass' initializer.
You are using wrong init
try this:
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap
{
self = [super initWithFrame: frame];
if (self) {
m_p = pWrap;
}
return self;
}
- (id)init {
self = [super init];
if (self) {
// initialize instance variables here
}
return self;
}
Having read Apple's documentation, I still am confused by the above. I am familiar with the concept of self and this in other languages, but here we are assigning self to superclass init self = [super init]; then checking if that returned nil or not. But then we are returning self in the last line. I mean, usually returning self means "I am returning myself" but here since we assigned self to super init earlier, aren't we returning super as self instead of ourselves as self?
Edit - I have tried to be as clear as possible above but using self in a sentence is tricky. Hopefully, someone can help.
No!
Every initializer must call [super init]. This means the super initializer you are calling in your example does the same.
All these initializers can prepare the object as they need to do, so that it finally is ready to be used as the class inheritance describes it. They all work on the same object. (That's the point of OO. An object can do everything its (super)classes describe. So all (super)classes must initialize the object.)
self is nothing more than a pointer to the object the method/initializer is currently working on. It does not have a special meaning like "I am returning myself".
Be aware of that no init method allocates the object. This done with [AClass alloc].
self is the same as this in Java or C#.
The line
self = [super init];
is allowing the parent class to do it's initialization first. If everything is good (in other words, self != nil) then we can do any initialization we need to do.
Finally we return self.
You have to remember that self or ourselves as you describe it is made up of the initialization done by the parent class and this class.
Update
This class and parent class need to cooperate to initialize self. We need to give the parent class first shot by calling [super init]. When it's done it returns an object that we refer to as self. We then further initialize self with the values for the instance variables that this child class defines. But both initializers are working on the same object.
Let me put this in layman's language.
You must have read about Cars and how a Prius is an object of Car when studying object oriented programming.
You basically have a superclass Car from which all cars inherit, like Prius, Focus, etc. For Prius to be a car, in object oriented terminology, and inheritance, Prius must first inherit from Car, and then add Prius specific attributes/properties.
Same way, every class you make in Objective-C (and pretty much every object oriented programming language), you must first inherit from a parent class. The root class being NSObject (objective-c).
[super init] initializes the parent class, with all it's properties. After that is successful, you add your own attributes/properties, specific to your class.
A common example is when you override the init method when subclassing a UITableViewCell.
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Foo"]];
imageView.frame = CGRectMake(0, 0, 100, 50);
[self.contentView addSubview:imageView];
}
return self;
}
Here, initWithStyle:reuseIdentifier: is overridden. It first calls [super initWithStyle:style reuseIdentifier:reuseIdentifier]. This initializes a default UITableViewCell with the style and reuseIdentifier supplied to it. You have access to all properties of UITableViewCell here. Additionally, an imageView is added to the cell, which is specific to this cell only.
The Object Initialization document is really good to help understand this.
When we do self = [super init]; in our subclass's init method implementation,
I don't understand why it's not self= [[super alloc] init];
In the first case, how can you init something that you haven't allocate memory for?
Is this because you're not actually initing a superclass object but instead using the superclass's init method to init yourself first?
If so, where and when did we allocate memory for self?
Is it just assumed that we did the alloc somewhere else in our program before calling this init method?
Is the syntax basically saying [subclass initUsingMySuperClassImplementationFirst] ?
I don't understand why it's not self= [[super alloc] init];
Because when init is called, someone else has already allocated memory.
Note that alloc is a class method, and init is an instance method. When init is called, the object has already been created.
For example:
MyObject *someObject = [[MyObject alloc] init];
alloc creates and returns an allocated MyObject. init just sets things up - initializes any custom properties, etc.
This is equivalent to:
MyObject *someObject = [MyObject alloc];
someObject = [someObject init];
Is it just assumed that we did the alloc somewhere else in our program before calling this init method?
It's not just assumed, it's guaranteed - because it's impossible to get to init without doing so. For example, if you called:
MyObject *someObject = [MyObject init];
This wouldn't work, because init is an instance method, not a class method. (See What is the difference between class and instance methods? if you want to read more about the difference.)
The reason is because by the time your subclass's init method has been called, memory has already been allocated for it. You don't need to allocate memory for the superclass, as you are not instantiating it - you are calling the superclass's init method which already exists. There is a difference between allocation and instantiation.
This is the same paradigm as in other languages like Java. alloc is a class method, not an instance method, so the only way init can ever be called is if alloc has been called already.
Actually, calling [[super alloc] init] would likely produce an unnecessary leaked object, as you have allocated memory that will go out of scope at the end of init, which is a bad thing.
I have seen self = [super init] in init methods. I don't understand why. Wouldn't [super init] return the superclass? And if we point self = [super init], are we not getting self = superclass?
Here's an example code fragment
- (id)init
{
if (self = [super init]) {
creationDate = [[NSDate alloc] init];
}
return self;
}
Hope someone can clarify this for me. Thank you.
Assuming that MyClass is a subclass of BaseClass, the following happens when
you call
MyClass *mc = [[MyClass alloc] init];
[MyClass alloc] allocates an instance of MyClass.
The init message is sent to this instance to complete the initialization process.
In that method, self (which is a hidden argument to all Objective-C methods) is
the allocated instance from step 1.
[super init] calls the superclass implementation of init with the same (hidden)
self argument.
(This might be the point that you understood wrongly.)
In the init method of BaseClass, self is still the same instance of MyClass.
This superclass init method can now either
Do the base initialization of self and return self, or
Discard self and allocate/initialize and return a different object.
Back in the init method of MyClass: self = [super init] is now either
The MyClass object that was allocated in step 1, or
Something different. (That's why one should check and use this return value.)
The initialization is completed (using the self returned by the superclass init).
So, if I understood your question correctly, the main point is that
[super init]
calls the superclass implementation of init with the self argument,
which is a MyClass object, not a BaseClass object.
As you have Question self = [super init] in the if Condition suggest a specific meaning.
First of all [super init] gives the initialization of the superclass of the existing class which is in use currently. Using [super init] gives the super class initialization which shows that object exist of the class.
Now when you use self = [super init] that means you are assigning the class to the self for the further utilization of the same class.
And at the end you put it in if condition as if(self = [super init]) this means you are checking whether the object of the class exist of not to prevent the foul behavior of the application.
I think it is clear now!!!
#MartinR has a very good answer. But do you ever wonder why "[super init] calls the superclass implementation of init with the same (hidden) self argument. (This might be the point that you understood wrongly.)" works in his 3rd point ?
Here is the excerpt from Big Nerd Ranch guide 3rd edition, chapter 2 Objective C that clarifies this point
“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 you send a message to super, you are sending a message to self,
but the search for the method skips the object’s class and starts at
the superclass.”
This code shows how iOS Runtime performs this task
objc_msgSendSuper(self, #selector(init));
Every method that you declare has two hidden parameters: self and _cmd.
The following method:
- (id)initWithString:(NSString *)aString;
is converted by the compiler to the following function call:
id initWithString(id self, SEL _cmd, NSString *aString);
see this link for more:
http://www.cocoawithlove.com/2009/04/what-does-it-mean-when-you-assign-super.html
Self = [super init];
According to JAVA, this mean a pointer to instance itself so object can message itself.
Same meainng of Self here in objective C,
According to JAVA, Super mean that allow to access base or parent class
Same meainng of Super here in objective C,
Now init instance to to complete the initialization process.
I would think of it as, init'ing all the supers variables etc, then you get to init your extended classes variables before it is returned.
[super init] is the same as [self superclass_variant_of_init]
If you want to send a message to superclass, there is another approach (without using runtime library):
[[self superclass] init];
From Apple's Documentation:
Because an init... method might return nil or an object other than the one explicitly allocated, it is dangerous to use the instance returned by alloc or allocWithZone: instead of the one returned by the initializer. Consider the following code:
id myObject = [MyClass alloc];
[myObject init];
[myObject doSomething];
The init method in the example above could have returned nil or could have substituted a different object. Because you can send a message to nil without raising an exception, nothing would happen in the former case except (perhaps) a debugging headache. But you should always rely on the initialized instance instead of the “raw” just-allocated one. Therefore, you should nest the allocation message inside the initialization message and test the object returned from the initializer before proceeding.
id myObject = [[MyClass alloc] init];
if ( myObject ) {
[myObject doSomething];
} else {
// error recovery...
}
Why would I use (inside my dealloc method)?
[myInstance release] instead of [self.myInstance release]
myInstance = nil instead of self.myInstance = nil
Although we use self.myInstance = [[[AClass alloc] init] autorelease] instead of myInstance = [[[AClass alloc] init] autorelease]?
Those practices are from numerous examples I see on the web.
1) [myInstance release] instead of [self.myInstance release]
prefer the former.
the returned value of self.myInstance is defined by implementation when a subclass has overridden the method myInstance. you're not interested in the behaviour of the interface of a constructed object during dealloc (since a subclass may override and return something other than your ivar).
what you are interested in dealloc is releasing the references you own before your object is destroyed. if the subclass has overridden myInstance, then it could:
a) return an ivar (declared in the subclass) that's already been released
or
b) the implementation of the override may return a newly created autoreleased object
either a or b could lead to an over-release and a crash (assuming everything else is correctly retained/released). this also suggests why you should assign nil to the ivar after releasing it.
this is also a classic example of how to trigger object resurrection. object resurrection occurs when an implementation of the getter/setter you call recreates its state after it's already been deallocated. the least offensive side-effect would cause a harmless leak.
2) myInstance = nil instead of self.myInstance = nil
again, prefer the former.
a formal response would look much like the response to #1 -- the rationale, side-effects and dangers apply here as well.
the safest way to handle this is to access the ivar directly:
[myInstance release], myInstance = nil;
because there may be really nasty side-effects (crashes, leaks, resurrection) which may be difficult to reproduce.
these dangers may be easily avoided and your code will be far easier to maintain. on the other hand, if people encounter the side-effects when using your programs, they will probably avoid (re)using it wherever they can.
good luck
Calling self.myInstance = uses the auto generated setter method. Calling [self.myInstance release]; calls release on the object returned by your getter method. It all depends on how your properties were set up (retain, assign?). There is no necessarily right or wrong answer to your question, since it all depends on the property in question. I suggest you read up on Objective C properties to get a better feel for this kind of thing.
And, unless myInstance was declared with assign, you wouldn't want to call self.myInstance = [[AClass alloc] init] You'd be much better off with self.myInstance = [[[AClass alloc] init] autorelease]
Note that using
myInstance = nil
instead of
self.myInstance = nil
Is incorrect (in the context of say a viewDidUnload method in a UIViewController subclass) if myInstance is a retain property, since if myInstance points to an object, it will be leaked!
This depends on a property that you defined in interface. For example if you define retain property:
#property (nonatomic, retain) NSObject *property;
then you may use just self.property = nil; in dealloc method, because it equals to:
[property release]; // releases previous property
property = [nil retain]; // [nil retain] returns just nil
The very same thing with self.property = [[A alloc] init];. This equals to
[property release]; // releases previous property
property = [[[A alloc] init] retain];
in case of property = [[A alloc] init]; property won't be retained.
Here's a full properties guide form Apple.
Actually using
self.myInstance = [[AClass alloc] init];
will lead in a memory leak, cause self.myInstance is using setter methods which leads in retain +1 along with alloc/init retain +1. So you'll get a retain count +2;
... = self.myInstance
and
self.myInstance = ...
are actually subroutine or method calls to getters and setters, which depending on how you define these subroutines, or have Objective C Properties create them, could do almost anything.
If the case of retain properties, the subroutines might play with the retain counts. If you do your own getters and setters, you could have them control the lights in your house, turning them on for none zero sets and turning the lights out when setting something to zero or nil. There doesn't even need to be a backing variable named "instance" which could be set by:
instance = ...