memory/pointer behavior for self = [super init] - objective-c

Forgiveness, please: I am a beginner. I was looking at another quesiton/answer and came across this code:
SpinningView *spinner = [[SpinningView alloc] initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)]
// Now let's take a look at the implementation of SpinningView's -initWithFrame: method
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor clearColor];
}
return self;
}
I believe that, in the second section of code, self points to the instance to which the message was sent that resulted in "self" being encountered, i.e., the result of [SpinningView alloc]. (Or doesn't that produce an instance?)
So, when you call self = [super initWithFrame:frame] on the 4th line of code, are you not reassigning the pointer value associated with "spinner"? I.e, are you not abandoning the memory you allocated in the first line? Or does the compiler someone know just to copy memory values instead of changing the pointer value? Or... what??
Thanks!

This is the standard idiom for the -init method of obj-c objects. The idea being that, whatever was allocated from +alloc doesn't matter, only what was returned from -init matters. Now, -init will usually just use the already-allocated object that's in self. But it's not required to. It is free to deallocate that object and create a new one. The classic example is when you alloc/init an NSString* you don't actually get back an instance of NSString*, you get back a concrete subclass. This is because NSString* is a "class cluster". So when you call +alloc you get back an NSString*, but when you call -init it frees that object and reallocates an object of one of its subclasses, initializes that new object, and hands it back to you.
Another example would be if you had a class that tried to memoize itself. Lets say you have an immutable class that gets initialized with a number. You could change your -init to re-use existing instances of the class. Here's an example (note: not thread-safe):
static NSDictionary *numberCache;
#interface MyNumber : NSObject
#property (readonly) int number;
- (id)initWithInt:(int)i;
#end
#implementation MyNumber
+ (void)initialize {
if (self == [MyNumber class]) {
numberCache = [[NSDictionary alloc] init];
}
}
- (id)initWithInt:(int)i {
// find ourself in the numberCache
NSValue *val = [numberCache objectForKey:#(i)];
if (val) {
// yep, we exist. Release the just-allocated object
[self release];
// and retain the memoized object and stuff it back in self
self = [[val nonretainedObjectValue] retain];
} else if ((self = [super init])) {
// nope, doesn't exist yet. Initialize ourself
_number = i;
// and stuff us into the cache
val = [NSValue valueWithNonretainedObject:self];
[numberCache setObject:val forKey:#(i)];
}
return self;
}
- (void)dealloc {
// remove us from the cache
[numberCache removeObjectForKey:#(_number)];
[super dealloc];
}
#end

#KevinBallard covered most of the points. The reason we need the self = is because init is not guaranteed to return the same object it is called on (it could return a different object or nil). I will answer your questions and expand on the memory management aspects:
I believe that, in the second section of code, self points to the
instance to which the message was sent that resulted in "self" being
encountered, i.e., the result of [SpinningView alloc].
Yes
So, when you call self = [super initWithFrame:frame] on the 4th line
of code, are you not reassigning the pointer value associated with
"spinner"?
Yes. Not spinner (spinner doesn't exist at this point anyway). You are re-assigning the pointer variableself inside the method.
I.e, are you not abandoning the memory you allocated in the first
line? Or does the compiler someone know just to copy memory values
instead of changing the pointer value? Or... what??
Yes. Under MRC, you are just re-assigning the pointer, and the compiler does not do anything except change the pointer value. Under ARC, it's more complicated, but at the end of the day, the compiler just does the same as under MRC in this case, i.e. just re-assigns the pointer.
It's not really "abandoning" the memory if you think about it. You see, by convention, init methods take ownership of ("consume") an already-retained object that they're called on (usually the return result of a call to alloc), and they return a retained object. But these two don't have to be the same object. So when your init method is called, its self is already retained, and the init method owns it, but then it calls [super init...], which calls the superclass's init method on self, so that method now takes ownership of the self which your init had ownership to. And in return, that superclass's init returns back to you a retained instance, which you assign to self. You did not "abandon" self because you gave it to the superclass's init method, which in turn became responsible for memory managing it (including releasing it if it wants to return something else).

Related

Followup to returning nil from a [[class alloc] init]

As follow-up of sorts to Is returning nil from a [[class alloc] init] considered good practice?, there's a case that I haven't seen any discussed much: what to do with an init that fails some preconditions before it can call the next init?
Example, suppose in this initWithStuff: method being passed nil or in general having no value to pass to initWithValue: is an absolute failure and we definitely want to return nil.
- (id)initWithStuff:(Stuff *)inStuff {
if (!inStuff || ![inStuff hasValidValue])
{
// can't proceed to call initWithValue: because we have no value
// so do what?
return nil;
}
NSInteger value = [inStuff integerValue];
return [super initWithValue:value];
}
Perhaps a clearer example is if the designated initializer method we wrap takes an object pointer and throws an exception if its passed nil. We definitely need to short-circuit that init call that would cause an exception.
My guess: init by any means possible, and only then release self before returning nil. If necessary, call bare init or any other initializer that will work to finish putting self into a known state before releasing it.
// can't proceed to call super's initWithValue: because we have no value
// so do what? do this:
self = [super init]; // or initWithValue:0
[self release];
return nil;
And if there were no such initializer that will work without valid data, I guess one would need to construct some valid, dummy data. Or complain to its author and until then just return nil and live with the leak :^)
Also, how does ARC affect the situation?
My guess: still finish init by any means possible, then just return nil. You'd think setting self might be redundant, but in some cases it's not. In any case, it but it needs to be there to silence a compiler warning.
// can't proceed to call super's initWithValue: because we have no value
// so do what? do this:
self = [super init]; // finish init so ARC can release it having no strong references
return nil;
Are my guesses wrong in any way?
Ideally, if a precondition fails, you don't call [super init…]. You just release self (if not using ARC) and return nil:
- (id)initWithStuff:(Stuff *)stuff {
if (!stuff || ![stuff isValid]) {
[self release]; // if not using ARC
return nil;
}
if (self = [super init]) {
// initialization here
}
return self;
}
The release takes care of deallocating self under MRC. Under ARC, the compiler will insert the release for you.
However, there is a potential problem with this approach. When you release self (or when ARC releases it for you), the system will send the dealloc message to the object. And your dealloc method will call [super dealloc]. You could suppress the [super dealloc] under MRC, but you can't avoid it with ARC.
So the danger is that your superclass might assume that one of its instance variables has been initialized, and rely on that initialized value in its dealloc. For example, suppose this is the superclass:
#interface SomeSuperclass : NSObject
#end
#implementation SomeSuperclass {
CFMutableBagRef bag;
}
- (id)init {
if (self = [super init]) {
bag = CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks);
}
return self;
}
- (void)dealloc {
CFRelease(bag);
}
#end
The problem here is that CFRelease requires its argument to not be nil. So this will crash during deallocation if you don't call [super init] in your subclass.
Given this problem, I have to change my initial recommendation. If you know that your superclass's dealloc doesn't have this sort of problem (because, for example, it checks pointers before dereferencing them or passing them to CFRelease), then you can safely not call [super init].
If you don't know that your superclass's dealloc is safe, then my recommendation is that you move your preconditions out of init and into a class factory method.
In other words, don't treat alloc/init as part of your class's public interface. Provide a class method for creating instances:
// The class factory method. Declare this in your header file. This is how you
// or any user of this class should create instances.
+ (id)myObjectWithStuff:(Stuff *)stuff {
if (!stuff || ![stuff isValid])
return nil;
// self here is the class object, so it's appropriate to send `alloc` to it.
// You don't want to hardcode the class name here because that would break
// subclassing.
return [[self alloc] initWithStuff:stuff];
}
// This is now considered a private method. You should not declare it in your
// header file, though in Objective-C you can't prevent the user from calling it
// if he's determined to.
- (id)initWithStuff:(Stuff *)stuff {
// Precondition was already checked in myObjectWithStuff:.
if (self = [super init]) {
// initialization here...
}
return self;
}

Why in Objective-C, we use self = [super init] instead of just [super init]?

In a book, I saw that if a subclass is overriding a superclass's method, we may have
self = [super init];
First, is this supposed to be done in the subclass's init method?
Second, I wonder why the call is not just
[super init];
? I mean, at the time of calling init, the memory is allocated by alloc already (I think by [Foobar alloc] where Foobar is the subclass's name. So can't we just call [super init] to initialize the member variables? Why do we have to get the return value of init and assign to self? I mean, before calling [super init], self should be pointing to a valid memory allocation chuck... so why assigning something to self again?
(if assigning, won't [super init] just return self's existing value?)
So why assign the value returned from [super init] to self? Looking at
a typical initializer method:
- (id)initWithString:(NSString *)aString {
self = [super init];
if (self)
{
instanceString = [aString retain];
}
return self; }
Why do we assign [super init] to self here?
The textbook reason is because [super init] is permitted to do one of
three things:
Return its own receiver (the self pointer doesn't change) with
inherited instance values initialized.
Return a different object with
inherited instance values initialized.
Return nil, indicating failure.
In the first case, the assignment has no effect on self and the
instanceString is set on in the original object (the line
instanceString = [aString retain]; could have been the first line of
the method and the result would be the same).
In the third case, the initialization has failed. self is set to nil,
no further action is taken and nil is returned.
The rationale for assigning to self is associated with the second
case: if the returned object is different, we want the:
instanceString = [aString retain]; which gets converted to
self->instanceString = [aString retain]; to act on the correct value,
so we have to change the value of self to point to this new object.
hoping this helps...
From Cocoa with Love
A classic example of returning a different object from -init is in implementing a class cluster - an abstract interface with multiple concrete implementers providing different storage or algorithms. +[NSString alloc] returns an instance of NSPlaceholderString. The initialisers of the placeholder instance inspect their parameters, release the placeholder string and return an initialised instance of a concrete NSString subclass.
It is possible the superclass might decide the object can't be initialised properly and return nil as a failure. If you don't assign nil to self your init method will carry on under the assumption that the parent class has correctly initialised the object.
It is also possible for the parent class to also return a completely different object if it wants.
Understand that the object is already alloced and self points to a memory.
Now [super init] does the initialization part.
1) If initialization is successful self points to same object before initialization
2) If initialization is failure init function returns nil and self = nil. Now we can check whether object is initialized and if yes do our magic by this code
if(self = [super init]){
// do our magic
}
IT is just like we use an imageView, we normally use
UIImageView imgView = [[UIImageView alloc] init];
imgView will only have non nil value if both alloc and init is succesful.

(Objective-C)Is it safe to redefine self within class method?

Is it safe to reinitialise self within a class method?
MyClass * a = [[MyClass alloc]init];
#implementation MyClass
{
-(id)init
{
if(self = [super init])
{
...
}
return self;
}
-(void)redefine
{
//??
self = [self init];
}
}
will a point to the reinitialized instance of MyClass?
Thank You,
nonono
Provided that (a) your class and its superclasses can be re-init'ed without leaking memory or resources and (b) you know that your class and its superclasses inits all return the self they are passed and not a reference to some other object, then yes...
Otherwise things will go wrong. Consider your redefine method; in the body of this method self is just a local variable whose contents is initialized to point to some object. Changing the value in that local variable does not change the object it originally pointed at, or the value of any other variables which point to that object. E.g. consider the variation:
#implementation Q
{
- (void) redefine
{
self = [[Q alloc] init]; // changes the *local* self to refer to a new object
}
...
}
...
Q *someQ = [[Q alloc] init]; // allocate an object
[someQ redefine]; // NO effect on someQ, another Q is just created and leaked
Clearly this does not alter someQ, and your version may not either. Your code will have the effect you wish if and only if you know init always returns the object it was passed - which is not guaranteed in Obj-C.
As long as init returns self, which it normally does, nothing will go wrong.
But you probably want to split your initialization to some separate method, which you can call from both init and redefine.
You need to return your new object from -init, not simply assign a new value to self. And you must remember to release the old self, since it was created with +alloc. Caveats aside though, returning a different object from -init is explicitly allowed. That's why you'll see newbies being corrected when they write something like this:
// Bad example! Do NOT do this!
Foo *foo = [Foo alloc];
[foo init];
This is an anti-pattern because -init is not required to return the same object it was called on. That means the above can end up assigning foo to point to an object that's been released, instead of to the object that was initialized in its place. This is why you always see +alloc and `init chained together like so:
Foo *foo = [[Foo alloc] init];
It's also why you need to reassign self when calling super's -init, because it may also have returned a different object.
self = [super init];

Assign the return object of the superclass to self

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.

Why should I call self=[super init]

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.
You mean why
self = [super init];
rather than
[super init];
Two reasons:
in initialisation, failure is indicated by returning nil. You need to know if initialisation of the super object failed.
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.
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:
Return its own receiver (the self pointer doesn't change) with inherited instance values initialized.
Return a different object with inherited instance values initialized.
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
Singleton object (always returns the singleton instead of any subsequent allocation)
Other unique objects ([NSNumber numberWithInteger:0] always returns the global "zero" object)
Class clusters substitute private subclasses when you initialize an instance of the superclass.
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.
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.
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.
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.
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.