In ARC, why is self in init methods a consumed parameter? - objective-c

I want to understand ARC, and I'm reading this:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#consumed-parameters
It says that a consumed parameter is retained before the call, and released at the end of the function (inside the function body). It then says that init... methods are effectively marked with ns_consumes_self. I don't see the point.
Foo *foo = [[Foo alloc] initWithWhatever: x];
So alloc returns an object with a retain count of 1, right? Now it is retained again before going into init, and then released at the end of init, so we're back at 1. Why is it designed like this? When I think about what the typical init looks like, I get more confused.
self = [super init];
if (self) { ... }
return self;

So alloc returns an object with a retain count of 1, right? Now it is
retained again before going into init, and then released at the end of
init, so we're back at 1. Why is it designed like this?
Probably because initializers are free to return a pointer to a different object than the one that self points to initially. An -init method can say: I don't like this object, I think I'll substitute a different one and that's perfectly OK. Before ARC, such an initializer would explicitly release self (even though it never retained it) and then assign some other pointer to it. Presumably, the ns_consumes_self directive will take care of releasing the object that was passed into the initializer even if self is changed to point to some other object inside the method.
When I think about what the typical init looks like, I get more confused.
It's a good bet that the behavior is there to cover cases that don't look like a typical -init method. Modifying self isn't exactly typical, it's just permissible.

Why shouldn't it be that way? Calls to -init are meant to return a given object with a +1 retain count, and doing a "temporary retain" is the safest way of guaranteeing that self remains alive throughout the entirety of a given init method. Consider what happens if we peel back the layer of Objective-C abstraction and turn -init into the function pointer it's IMP resolves to:
id init(id self, SEL _cmd) {
//+0 self given requires explicit retain to guarantee lifetime
//...
//(if retained) +1 self is returned; (if not retained) +0 self is deallocated
}
If given a self with a +0 retain count (as is common in most methods that retain their arguments i.e. setters), then you would have to guarantee that somewhere up the inheritance chain someone was nice enough to retain self away from whatever happened to allocate it (ending in self having a rather ambiguous retain count of +1). But, if you receive a self with a +1 retain count, and you do a retain-release it yourself,you can be certain that it remains alive through your -init method, and that you and you alone have ownership of self. And if the given self was not "alive", then you're guaranteed to return nil rather than an object in the middle of deallocation. Thus, the above becomes (in pseudo-C):
id init(__attribute((ns_consumed))id self, SEL _cmd) {
//implicit retain of +1 self returns self with +2
//...
//implicit release of +2 self returns self with +1
}
I like to call this pattern "old-school atomic access", and it's used in Apple frameworks designed before #synchronized {} atomic getters were invented. When you use a getter backed with a public iVar. You'll often see methods that follow that pattern written like:
- (NSView *)view {
//explicit retain-autorelease of +1 variable is +2 -> +1, guaranteed access or nil.
return [[_view retain]autorelease];
}
But all of this doesn't touch the ownership rules of the exception that is -init and family. -init methods return objects +1, but who exactly owns them? Well, the allocator* still has a hand in the reference to the variable, and self = [super init] doesn't actually retain anything (and it also has to obey the whole "returns +1" rule). Well, again I have to turn to pseudo-code, but this time it'll be in Objective-C:
- (id)init {
//self is +1 because -init must return +1
self = [super init];
//implicit [self retain]; leaves self with a +2 reference count
//...
//implicit [self autorelease]; leaves self with a +1 reference count
return self;
}
OK, so now you've got a +1 object floating around claimed by the allocator, so how do you "claim" it? Assignment, of course! The point of implicitly __strong locals and __strong properties is to reclaim the object from the allocator entity.
- (void)f {
//Freestanding +1 variable is not owned by the caller, will be deallocated when the method
//passes out of scope.
[[NSObject alloc]init];
//Implicitly __strong local captures reference away from allocator entity,
//which "autoreleases" it's ownership
//We now "own" the returned object.
NSObject *obj = [[NSObject alloc]init];
//Strong property captures reference away from local, saves the object from being deallocated
//when the method passes out of scope
self.object = obj;
}
*Allocator, in the context of this answer, refers to the functions that eventually call malloc() to allocate space for the object.

Related

Understanding the init syntax

I've read quite a few different posts about overriding the init method hoping to find answers for a couple of syntax questions I've been unable to figure out.
(id) init
{
self = [super init];
if(self){
}
return self;
}
So when we send the init method to the superclass of our subclass (let's assume superclass is NSObject) we are initializing all the instance variables inherited from the superclass? What else does this accomplish?
Whenever we create a new class, are we always inheriting instance variables from the parent class? For instance if I create a class called Fraction...
Fraction : NSObject
Fraction * myFrac = [[Fraction alloc] init]
Does the object that myFrac is referencing automatically inherit instance variables that I haven't even declared yet from the parent class?
Lastly when doing
self = [super init];
Aren't we initializing the superclass? What exactly are we storing in self? Is the result of init a pointer to our newly initialized object of our subclass?
I know this has been asked quite a few times, but I couldn't find these answers in the explanations. Sorry for the pileup of questions.
So when we send the init method to the superclass of our subclass
(let's assume superclass is NSObject) we are initializing all the
instance variables inherited from the superclass?
By default all ivars are set to nil/NULL/0/0.0/NO, depending on their type, yet your parent class may want to have them set to something else by default, in that case it will change their value in its init method.
What else does this accomplish?
Whatever NSObject (or your parent class) wants to do when a new object is initialized. Basically the convention says, you must not use an object that has not been initialized (with the exception of release - you may release an object that has never been initialized, that is explicitly allowed). Most other languages know the concept of contsructors, e.g. in Java you'd say new String(...) to create a string object, which does two things: It creates a new string object and it initializes the object by calling its constructor. Java will not allow you to do one thing without doing the other one. In Obj-C these two things are individual steps. alloc creates a new object and init initializes it. Offering two separate steps has advantages in some cases, but it also has the disadvantage that you must rely on conventions (init must be called before the object may be used, yet it must never be called more than once; the compiler will enforce neither one, though, at least not last time I checked that).
Whenever we create a new class, are we always inheriting instance variables from the parent class?
Yes; unless NSObject doesn't have any. Most ivars in Obj-C are private, protected is already a huge exception and you hardly ever see public ones. So basically you should never directly access the ivar of your parent class and thus you don't really have to care if you inherit any or none.
self = [super init];
Aren't we initializing the superclass? What exactly are we storing in
self? Is the result of init a pointer to our newly initialized
object of our subclass?
An init method is allowed to return a different object than the one the method has been called for. E.g. the following is valid:
static MyClass * ThereIsOnlyOneIstance;
- (id)init
{
if (ThereIsOnlyOneInstance) {
[self release];
return [ThereIsOnlyOneInstance retain]; // Without retain if using ARC
}
self = [super init];
if (!self) return nil;
ThereIsOnlyOneInstance = [self retain]; // Just `= self` if using ARC
return self;
}
The following two if-statements will be true:
MyClass a = [[MyClass alloc] init];
MyClass b = [MyClass alloc];
if (a != b) NSLog(#"a != b will be true");
b = [b init];
if (a == b) NSLog(#"Now a == b will be true");
Also an init method may fail, in which case it must release the object and return nil. So when calling [super init] this method may fail. Don't think too much about why it may fail, just keep in mind that it may fail. Now assume that you write the following code:
- (id)init
{
[super init]; // BAD!!! THIS IS BROKEN!!!
// Recent versions of CLANG will even make this
// a hard compiler error and refuse to compile that.
return self;
}
If [super init] failed, the object has been released and nil was returned, but you haven't updated self, you just return whatever value used to be in self prior to calling [super init]. As a result, you return a pointer to a dead object, since at the memory location self points to is no object any longer, this is a dangling pointer and using it can cause your app to crash or otherwise malfunction.
That's why you always must write the output of another init method back to self. Same is true for calling init from outside. The following code is broken:
MyClass x = [MyClass alloc];
[x init]; // BAD!!! THIS BROKEN!!!
It is broken, since init may release the object x points to, so x is now a dangling pointer. You always must capture the output of init back to the variable that should point to the object. The following code is correct:
MyClass x = [MyClass alloc];
x = [x init];
Though usually you alloc/init in just one combined call, of course:
MyClass x = [[MyClass alloc] init];
but that's actually the same, the compiler generated code will look no different than before.
So when we send the init method to the superclass of our subclass
(lets assume superclass is NSObject) we are initializing all the
instance variables inherited from the superclass? what else does this
accomplish?
No. The runtime initializes all variables in an Objective-C context to nil for you (rather than a garbage value without explicit initialization under the C and C++ runtimes). -init exists for setup, and it actually unnecessary for direct subclasses of NSObject, as the default -init method returns self and exits. That said, -init and those methods in its family are often necessary to initialize the member variables and setup state of objects further down the inheritance chain. Don't think of it as a companion to +alloc, rather just a handy setup method that's become the norm in the language.
Does the object that myFrac is referencing automatically inherit
instance variables that I haven't even declared yet from the parent
class?
If by "inherits" you mean that any variables you create still maintain the offset that their superclass hands them, then yes. If by "inherits" you mean "gives access to", then it depends. The #public, #private, and #protected directives determine the access rights a derived class gets to the instance variables of its parents.
Aren't we initializing the super class?
Yes, but understand that init and friends do not actually allocate memory, or setup anything language-specific. They just setup, hand off self, and walk away.
What exactly are we storing in self?
We're storing the object allocated by +alloc and returned to us by NSObject in the form of self. Calling through to super just gives the superclass an opportunity to run its setup, then pass us back a self pointer so we can do our setup.
Is the result of init a pointer to our newly initialized object of our subclass?
Oh, I sure hope so.

memory/pointer behavior for self = [super init]

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).

Object's ownership, after "return". Clarification needed

Assuming, the following declaration for class A
#property(nonatomic, assign) DoublyLinkedList *doublyLinkedList;
, that as part of init, initialized the object
- (id)init {
self = [super init];
if (self) {
doublyLinkedList = [[DoublyLinkedList alloc] init];
}
return self;
}
and that a method
- (DoublyLinkedList*) doSomethingAndReturn {
that ultimately
return doublyLinkedList;
Does class A owns the doublyLinkedList after the return?
EDIT: init added with alloc
You are not calling retain on it, but in init you are calling alloc on it, so it does have a retain count of 1 -- you own it and you should release it in dealloc.
You could simply alloc it and release it in dealloc. The caller of the property can choose whether to retain. Another option would be to create the object in init, autorelease it and then assign it to the property with (retain) instead of (assign). That way, if other places in the code alloc and assign to that property, the object you alloc'd will get released. Then in dealloc, what it's currently assigned to will get released.
Yet another option if you don't want others to set it would be to have a (readonly) property and a _doubleLinkedList iVar and then #synthesize doublyLinkedList = _doubleLinkedList. Then you can allocate it once in init and know that no one else will assign it, and then release it in dealloc.
A good analogy is that when you retain, you're putting a leash on it. Multiple items can put a leash on that object. It is freed only when everyone has taken the leash off.
A good guide to read:
Apple's Memory Management Programming Guide
Specifically from that doc, these rules help:
You own any object you create You create an object using a method
whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for
example, alloc, newObject, or mutableCopy).
You can take ownership of an object using retain A received object
is normally guaranteed to remain valid within the method it was
received in, and that method may also safely return the object to its
invoker. You use retain in two situations: (1) In the implementation
of an accessor method or an init method, to take ownership of an
object you want to store as a property value; and (2) To prevent an
object from being invalidated as a side-effect of some other operation
(as explained in “Avoid Causing Deallocation of Objects You’re
Using”).
When you no longer need it, you must relinquish ownership of an
object you own You relinquish ownership of an object by sending it a
release message or an autorelease message. In Cocoa terminology,
relinquishing ownership of an object is therefore typically referred
to as “releasing” an object.
You must not relinquish ownership of an object you do not own This
is just corollary of the previous policy rules, stated explicitly.
Objects aren't really "owned" in that way. Objective-C will free up the memory for an object when its retain count gets to 0. If class A depends on doubleLinkedList being "kept alive" as long as an instance of class A is alive, then object A retains doublyLinkedList to increase that retain count by 1. When object A returns a reference to doublyLinkedList as you have above, then the caller who receives that result may elect to retain the object as well, which would increase the retain count by one again.
So try not to think of it as owning an object. Instead, think of it as expressing an interest in the existence of an object. As long as someone continues to be interested in that object, as expressed by its retain count, then the object will not be deallocated.
As you've defined it, class A has not ever retained doublyLinkedList. So no, it has no stake in it. In fact because doublyLinkedList is not retained by class A, it could be deallocated at any time during execution and cause an EXEC_BAD_ACCESS crash.
There are two obvious ways to deal with this.
Class A should retain doublyLinkedList while it's using it, and autorelease it before it returns it.
Another 'parent' object can retaining both doublyLinkedList and the instance of class A, and it's up to that 'parent' object to make sure doublyLinkedList doesn't get deallocated while the class A object is using it.
Edit:
If you alloc-init the object when you initialize Class A, as you've added above, then you should only release the object when Class A is deallocated. This makes for a simple object life-cycle. An instance of Class A is created, it creates a DLL object. That object persists until the Class A instance is destroyed. If other objects want to use the DLL, they simply request it from the class A instance, and retain it.
The goal with retain release is to code in such a way that you can be sure you have an EVEN number of retain calls, and release calls on an object. For every:
- (id)init {
self = [super init];
if (self) {
doublyLinkedList = [[DoublyLinkedList alloc] init];
}
return self;
}
You need a:
-(void)dealloc {
[super dealloc];
[doublyLinkedList release]
}
If your class a object is going to be creating and processing more than one DLL object, then don't create it in -(id)init and use retain for the property declaration.
then:
ClassA *newClassAObject = [[ClassA alloc] init]; // create class a object
newClassAObject.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease]; // make a DLL object, only retained by class a object.
DoublyLinkedList *dll = [newClassAObject doSomethingAndReturn]; // process the list somehow
[dll retain] // we own this now
newClassAObject.doublyLinkedList = nil; // class A object gives up interest in dll.
newClassAObject.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease]; // now process another one.
... and on and on ...

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.