Objective C class initialization - objective-c

+ (id)packetWithType:(PacketType)packetType
{
return [[[self class] alloc] initWithType:packetType];
}
- (id)initWithType:(PacketType)packetType
{
if ((self = [super init]))
{
// code
}
return self;
}
Why do we need first class method, isn't second one just enough for initialization ??

There are two reasons for having convenience constructor class methods. The first one is, that the idiom of [[Thing alloc] initWithFoo: xyz] is really common but inconvenient to have to type anywhere. So, [Thing thingWithFoo: xzy] is a common abbreviation.
A deeper reason has to do with reference counting. Methods starting with init are supposed to return a reference of the instance, ownership of which is transferred to the caller. Wheras the convenience class methods usually return autoreleased references:
+ (id)packetWithType:(PacketType)packetType
{
return [[[[self class] alloc] initWithType:packetType] autorelease];
}
This is important to know in order to avoid dangling references and/or memory leaks:
Thing* thing = [[Thing alloc] initWithFoo: xyz];
// Now, *I* own the reference and *I* am responsible for releasing
// it, when I no longer need it.
[thing release]
On the other hand, the reference returned by
Thing* thing = [Thing thingWithFoo: xyz];
is owned by the "nearest" NSAutoreleasePool. The caller is not responsible for releasing it (in fact, that would be wrong!). If the reference is to be kept around, the caller must actually retain it here:
self->myMember = [thing retain];
You should know about these conventions even when using ARC, as the underlying rules are still in effect, even if (under ARC) it's the compiler, who generates the code to obey them. The NARC acronym is a nice way to remember, which method name prefixes come with certain responsibilities. This answer has the details.

Convenience constructors have their place in the language for some reasons. Of course using them is usually shorter but there are other advantages as well:
The object is not yet allocated when they are called so the method can decide which class to allocate. Class clusters might use this to find the proper class depending on the parameters of the constructor.
The method might also decide to return an already existing object from a shared cache.
The return value can be statically typed.
Note that your convenience constructor would typically be:
+ (Packet *)packetWithType:(PacketType)packetType
{
return [[self alloc] initWithType:packetType];
}
Now the return type is statically typed and we don't send the (redundant) class message to the class object. With recent compiler versions one could use instancetype as the return type.

Related

Simple rules for naming methods, compatible with ARC naming conventions

I have difficulties understanding naming conventions of ARC. I have always coded with ARC, and I guess this is the reason.
1. Class methods
What name should I choose for the following method?
What are the differences, concerning memory management, between theses two names?
This name:
+ (MyObject *)newObjectFrom:(MyObject *)anObject
withOptions:(NSDictionary*)options
{
MyObject * newObject = [anObject copy] ;
[newObject modifyWith:options] ;
return newObject ;
}
or this name ?
+ (MyObject *)objectFrom:(MyObject *)anObject
withOptions:(NSDictionary*)options
{
MyObject * newObject = [anObject copy] ;
[newObject modifyWith:options] ;
return newObject ;
}
2. Instance methods
What name should I choose for the following method?
What are the differences, concerning memory management, between theses two names?
This name:
- (MyObject *)newObjectwithOptions:(NSDictionary*)options
{
MyObject * newObject = [self copy] ;
[newObject modifyWith:options] ;
return newObject ;
}
or this name?
- (MyObject *)objectwithOptions:(NSDictionary*)options
{
MyObject * newObject = [self copy] ;
[newObject modifyWith:options] ;
return newObject ;
}
2. Simple rules for naming methods
Is there a basic, simple rule to follow when naming methods?
By "basic, simple", I mean
a rule similar to "strong when the object belongs to the class", "weak when the object is just referred to by this class, and (thus) owned by another class";
(and/or) a rule that does not refer to the memory management without ARC;
(and/or) a rule that does not use words such as "autorelease", "release".
When Rivera said that method names are not important, he probably followed his experience: It always works. And this is correct. And you are correct that you probably do not understand the role of method names because you has always used ARC. So what is the big deal with it?
I added a synopsis to show the problem with MRR at the end of this answer. As you can see there, you do not have to care about naming rules using ARC the way you had to with MRR.
To give you a more detailed explanation, you have to understand what happens using MRR:
Prior to ARC one had to do memory management manually. Doing so he had to know, what kind of ownership a return value has. To make a long story short, one had to know, whether he has to release a returned object:
Rule 1: You do not own an object returned by a method automatically. If you want to hold it, retain it and release it, when you are done with it.
id object = [[object methodThatReturnsAnObject] retain]; // I want to hold it
…
[object release]; // Done with it
id object = [object methodThatReturnsAnObject]; // I do not want to hold it
…
// I do not release it
Doing a deep analysis you can see that there are sometimes problems. (Object deallocation as a side effect.) But this was the basic approach.
The advantage of that was that a retain-release pair could be handled locally (inside a compound statement) and it was easy to follow the ownership of an object.
Rule 2: But when an object was created the first time this could not work: The sender of the message has always to hold it. Otherwise it would be destroyed immediately (= before the sender has the chance to retain it.) So there was a additional rule:
If the name of a class method that returns an object starts with alloc, init, or new you have to handle the returned object as you did a retain on it. Or in one word: Ownership transfer:
id object = [Class allocOrInitOrNewMethod];
…
[object release];
As -retain took the ownership explicitly, alloc–, init…, new… transferred it implicitly.
All other methods behaves like rule 1.
Rule 3: Sometime you need an autorelease pool.
To make the advantage of ARPs visible think of this code: (It is useless, just to demonstrate the problem
Case 1.1:
Person *person = [[Person alloc] initWithName:…]; // Ownership transfer, release person, when you are done
NSString *name = [person name]; // the name object is hold by the person object only
[person release]; // I do not need the person object any more
[name doSomething]; // Crash: The person was the only object holding the name
Another problem:
Case 2.1:
Person *person = [[Person alloc] initWithName:…]; // Ownership transfer, release person, when you are done
if (…)
{
return; // break, continue, goto
}
…
[person release];
Because the last line is never reached, the object is never released.
You can repair that with autoreleasing methods. An object moved to the ARP lives as long as the control flow returns to the run loop. So it lives through every method, through method return and so on. To do it explicitly:
Case 1.2:
Person *person = [[[Person alloc] initWithName:…] autorelease]; // No ownership transfer, persons belongs to the ARP
NSString *name = [person name]; // the name object is hold by the person object only
[name doSomething]; // No Crash: The person object holding the name object is still alive
Case 2.2:
Person *person = [[[Person alloc] initWithName:…] autorelease]; // No ownership transfer, prsons belongs to the AR.
if (…)
{
return; // break, continue, goto
}
…
// No release necessary.
Because one has to be too lazy to type such a long message chain, convenience allocators has been invented to do this for you:
+ (Person*)personWithName:(NSString*)name
{
return [[[self alloc] initWithName:name] autorelease];
}
With the result:
Case 2.3:
Person *person = [personWithName:…]; // No ownership transfer, persons belongs to the AR.
if (…)
{
return; // break, continue, goto
}
…
// No release necessary.
And you can do the same with getters:
- (NSString*)name
{
return [[_name retain] autorelease];
}
So we at the end of the day we have simple rules:
Rule 1: If you want to keep a returned object in memory retain it – and release it, when you do not need it any more.
Rule 2: If the class method's name starts with alloc, new, or init, think of it as an implicit retain (and therefore release it, when you are done with the object.)
Rule 3: Use -autorelease to delay the deallocation of returned objects for convenience.
Synopsis:
Alloc-init creation
// MRR:
Person *person = [[Person alloc] initWithName:#"Amin"];
…
[person release]; // You create it, you release it
// ARC:
Person *person = [[Person alloc] initWithName:#"Amin"];
…
New creator
// MRR:
Person *person = [[Person newPersonWithName:#"Amin"];
…
[person release]; // You create it, you release it
// ARC:
Person *person = [[Person newPersonWithName:#"Amin"];
…
Convenience allocator
// MRR:
Person *person = [[Person personWithName:#"Amin"]; // Autoreleased
…
// ARC:
Person *person = [[Person personWithName:#"Amin"];
…
As you can see, there is no difference for the three ways of object creation using ARC. So Riviera is right, when he said that this is not important any more. But under the hood the last way is different, because it moves the object to the ARP.
It is the same with the implementation of this methods:
Implementing a new allocator
// MRR
+ (Person*)newPersonWithName:(NSString*)name
{
return [[self alloc] initWithName:name];
}
// ARC
+ (Person*)newPersonWithName:(NSString*)name
{
return [[self alloc] initWithName:name];
}
Implementing a convenience allocator
// MRR
+ (Person*)personWithName:(NSString*)name
{
return [[[self alloc] initWithName:name] autorelease];
}
// ARC
+ (Person*)personWithName:(NSString*)name
{
return [[self alloc] initWithName:name];
}
Again the implementation for both methods is identical using ARC.
-> You do not need it any of this rules any more. ARC cares four you.
Especially you do not need convenience allocators any more, because there is nothing inconvenient any more. (And even they are optimized at run time, there is still a minimal runtime penalty.) I do not implement convenience allocators any more, but new allocators.
But ARC has to be compatible with MRR. So it remembers all that rules. To make your code readable for others you should repeat this rules, too. But, of course, now the implementation of a convenience allocator and a new allocator is bitwise identical – the rest is done by ARC.
Method names are important. The official documentation of how ARC interprets method names can be found in the clang ARC documentation in the section on method families.
Method naming conventions are important when converting the code from MRC to ARC, and when interoperating with MRC code from ARC Code.
Apple guide says that with "ARC code only" the naming conventions are "less important", but this is not 100% true.
For example (and this is only one example, I think that there are many other), look at this project
I swizzled release-autorelease calls to log it, and you can see the difference:
when a method begins with a special naming (for example "new"), ARC returns an object with a retain count of +1, that is balanced by release calls.
When a difference name is used, ARC returns an AUTORELEASED object. (look at the NSLog calls)
This can be a big difference in code that alloc a great number of objects in a loop. In this case, the programmer should create an autorelease pool.
So, it's not true that the naming conventions are less important when using ARC-only code.
I don't know all of the details on naming methods 100% conventionally because there are different situations that apply to each. however I think this article in the Apple docs will help you. https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html
My experience in the apple world is that factory methods like your examples would usually include 'create' by convention. This is probably less important now with ARC but in the old days 'create' in a method or function signature was a pretty sure fire way to be sure you understood you were taking ownership of the resulting object (owing a release/free() on it) rather than an instance type which you would assume to autorelease [NSArray array] , [UIColor colorWith....] etc, so I still definitely like to follow this convention.
ARC gave semantics to what used to be a naming convention for tracking reference counting responsibilities. So now the compiler uses the same naming patterns to determine whether a method returns a retained object, etc. See the link in #JodyHagens' answer and continue reading with http://clang.llvm.org/docs/AutomaticReferenceCounting.html#semantics-of-method-families
Methods in the alloc, copy, mutableCopy, and new families — that is, methods in all the currently-defined families except init — implicitly return a retained object as if they were annotated with the ns_returns_retained attribute. This can be overridden by annotating the method with either of the ns_returns_autoreleased or ns_returns_not_retained attributes.
The "new family" is the message selectors that start with "new" followed by an upper case letter. So there are memory management differences between newObjectFrom:withOptions: and objectFrom:withOptions:, but you can use an annotation to override that (don't go there), and the compiler should complain if you get it wrong.
(All methods that implement a given message selector had better provide the same reference counting semantics.)
In addition to Apple's article on Conventions that #iRebel_85 points out, Apple has an extensive set of naming guidelines.
Google's style guide adds a few more naming guidelines.
These guidelines are well thought out and useful for making code easier to understand and collaborate on.
First, memory management has nothing to do with the names you choose for your methods or classes. In other words if it compiles and you're not using reserved keywords or critical method names you should be good. (Please refer to Edit note)
As for 1, preceding new is very uncommon in Objective-C, so it's better to use objectFrom: instead.
Even better would be to be more precise about the kind of object you're creating. For example:
[NSArray arrayWithArray:]
[NSString stringWithFormat:]
Or in your case as you create a copy, and supposing you're creating "Client" objects:
[Client clientWithClient:options:]
Where with is not really needed.
For 2 I would choose:
copyWithOptions:
As you're more or less customizing [NSObject copy]. I would also implement only this method and delete the now redundant 1 as less methods is clearer, easier to document, and easier to maintain!
In case of doubt just search the SDK documentation to see how similar methods were named by Apple.
Edit:
In the first paragraph I don't mean to encourage bad naming practices, just to say that they are not the reason for your memory management concerns. Yet you should try to follow the naming conventions pointed in the other answers, or as I said, "do as Apple does".

Missing sentinel in method dispatch

I want to create a subclass of NSMutableArray and need to override the -initWithObjects: method.
But How to call [super xxx];?
- (id) initWithObjects:(id)firstObj, ... {
[super initWithObjects:firstObj]; // Error: Missing sentinel in method dispatch
// Error: The result of a delegate init call must be immediately returned or assigned to "self"
}
Thanks.
Then "missing sentinel" message refers to the missing nil termination. In fact, according to font-of-all-knowledge-Wikipedia:
The name of the nil that terminates a variable length list of parameters in Objective-C
also: Sentinel node, an object to represent the end of a data structure
also: Sentinel value, a value used to terminate a loop
also: In network protocols such as Bisync, sentinel values indicate where frames start and end
You can't. As discussed in the documentation for NSArray:
You might want to implement an initializer for your subclass that is
suited to the backing store that the subclass is managing. The NSArray
class does not have a designated initializer, so your initializer need
only invoke the init method of super. The NSArray class adopts the
NSCopying, NSMutableCopying, and NSCoding protocols; if you want
instances of your own custom subclass created from copying or coding,
override the methods in these protocols.
So you can assign self = [super init]; and add the objects from your initialiser to the resulting object. Indeed, because of the way that NSArray is implemented, calling any -initWith… method is likely to return an instance of a different NSArray subclass.
Notice that the documentation also discusses alternatives to subclassing NSArray that may be easier, more reliable or better in some other way.
Subclassing NSArray/NSMutableArray doesn't work like subclassing most classes. NSArray is a class cluster, please see subclassing notes from the NSArray documentation.
Now, for your specific question, subclassing va_list methods is a bit tricky, there are a number of ways to handle this. The 'safest' would be to process your va_list into an NSArray and pass that into another method that dealt with whatever you wanted. The other, slightly less portable, slightly hackier way is to create a new va_list list on the stack to pass through.
id __unsafe_unretained * stack = (typeof(stack))calloc(numOfObjects, sizeof(id));
//filloutStack
[super initWithObjects:*stack, nil];
free(stack);
Subclassing Apples Collection classes isn't that difficult — if you use a tiny trick (see also: cocoawithlove).
A subclass is a "is-a" relationship in object-orientated Design. But there are also "has-a" relationships, i.e. wrappers.
If you would try to create a subclass of NSArray by using a pure is-a relationship, I guess, it would be kind of hard, as you would have to do C-level memory management.
But if you add a has-a relationship — or: create a wrapper — at the same time, you can the subcalssing quite easily: Just make your custom array class have a member of a regular NSArray. Now override its method by forwarding the calls to the member object. I showed this in this post, where I just add objects, that pass a certain test.
But you will see, that I didn't implement the method you talked about correctly, but I raise a error. The reason is: that method is a variadic methods, that has a variable number of objects you can pass in — and to handle this, you have to to a bit of work. cocoawithlove has an great article about it.
For you — if using that has-a trick — it could look like
- (id) initWithObjects:(id)firstObj, ... {
if (self = [super init]) {
_realArray = [[NSMutableArray alloc] initWithCapacity:1];
}
va_list args;
va_start(args, firstObj);
for (id obj = firstObj; obj != nil; obj = va_arg(args, id))
{
[self.realArray addObject:obj];
}
va_end(args);
return self;
}
Try
self = [super initWithObjects:firstObj,nil];

Potential leak of an object warning -- clarification needed

After I Analyzed my code, Xcode indicated a potential leak as shown below.
Is this something I should be concerned about?
In this code, the class that sets doublyLinkedList is the sole owner and continues to manage this object throughout program execution.
The reason you're getting the warning is because the new call returns a retained object, and then your setter is probably doing another retain on it (depends on whether it's synthesized or manually generated).
Also, I would recommend you use the standard alloc/init instead of new, so that the two-phase creation is obvious.
This is better:
if (self) {
DoublyLinkedList *dll = [[[DoublyLinkedList alloc] init] autorelease];
self.doublyLinkedList = dll;
}
or just
if (self) {
self.doublyLinkedList = [[[DoublyLinkedList alloc] init] autorelease];
}
You may wish to do this instead:
if (self) {
DoublyLinkedList *dll = [DoublyLinkedList new];
self.doublyLinkedList = dll;
[dll release];
}
In the header, declare doublyLinkedList a #property that is retained.
You have a "potential leak" because the Analyzer sees that you have allocated memory for a DoublyLinkedList instance (using new), put it into a local variable called dll, and not released that memory in the same scope.
Assuming that the doublyLinkedList member that you're setting happens to also be a property declared as retaining, you also have an actual leak, because you have over-retained the DoublyLinkedList that you create here.
The ownership rules say that you have one claim on this instance because you called new to create it. When you pass the instance to setDoublyLinkedList:, it is retained, and you then have two claims. When the init method ends, you only have one reference to the instance, through the ivar/property -- you've lost the local variable -- which means that you have more ownership claims than you have references. This is a good indication that you will have a leak.
To fix the leak, you need to relinquish one of your claims before the end of the init method. You can do this in one of two ways, using release as soon as the property is set:
DoublyLinkedList * dll = [DoublyLinkedList new];
[self setDoublyLinkedList:dll];
[dll release];
or autorelease:
[self setDoublyLinkedList:[[DoublyLinkedList new] autorelease]];
// Or equivalent procedures involving a temp variable
However, it should be noted that using setters in init may be problematic (see also Mike Ash's writeup on the topic), because accessors can -- potentially -- have side effects that depend on your object already being fully set up. There seem to be two camps on this issue, and it's probably best to read about it and come to your own conclusions, but you may find that it simplifies your initializer methods to assign to ivars rather than using properties:
if( self ){
doublyLinkedList = [DoublyLinkedList new];
}
This is completely correct in terms of memory management.
Finally, if DoublyLinkedList is a class whose code you have, you can also consider writing a convenience constructor, which will return a new, autoreleased instance for you. The convention in Cocoa is to simply name the method after the class, with standard method name casing, like so:
+ (id) doublyLinkedList {
return [[[self alloc] init] autorelease];
}
Note that this is a class method:
if( self ){
[self setDoublyLinkedList:[DoublyLinkedList doublyLinkedList]];
}
and see my answer to "Self-allocating objects" for an explanation of these constructors.
If you have a property called "doublyLinkedList" (assumption based on code given), and it is "retained," you can do the following:
if (self) {
DoublyLinkedList *dll = [[DoublyLinkedList alloc] init]
self.doublyLinkedList = dll;
[dll release];
}

Why shouldn't I use the getter to release a property in objective-c?

I was told by a fellow StackOverflow user that I should not use the getter method when releasing a property:
#property(nonatmic, retain) Type* variable;
#synthesize variable;
// wrong
[self.variable release];
// right
[variable release];
He did not explain in detail why. They appear the same to me. My iOS book said the getter on a property will look like this:
- (id)variable {
return variable;
}
So doesn't this mean [self variable], self.variable, and variable are all the same?
For a retained property with no custom accessor, you can release the object by:
self.variable = nil;
This has the effect of setting the ivar (which may not be called 'variable' if you have only declared properties) to nil and releasing the previous value.
As others have pointed out, either directly releasing the ivar (if available) or using the method above is OK - what you must not do is call release on the variable returned from a getter.
You can optionally write custom getter behavior, which may result in completely different behavior. So, you cannot always assume that [variable release] has the same results as [self.variable release].
As well, you can write custom properties without an exclusive ivar backing them... it can get messy fast if you start releasing objects from references returned by getters!
There may be additional reasons that I'm unaware of...
A typical getter will look more like this:
- (id)variable {
return [[variable retain] autorelease];
}
So if you use [self.variable release] you have an additional retain and autorelease that you don't really need when you just want to release the object and that cause the object to be released later than necessary (when the autorelease pool is drained).
Typically, you would either use self.variable = nil which has the benefit that it also sets the variable to nil (avoiding crashes due to dangling pointers), or [variable release] which is the fastest and may be more appropriate in a dealloc method if your setter has custom logic.
not all getters take this form:
- (id)variable { return variable; }
...that is merely the most primitive form. properties alone should suggest more combinations, which alter the implementation. the primitive accessor above does not account for idioms used in conjunction with memory management, atomicity, or copy semantics. the implementation is also fragile in subclass overrides.
some really brief examples follow; things obviously become more complex in real programs where implementations become considerably more complex.
1) the getter may not return the instance variable. one of several possibilities:
- (NSObject *)a { return [[a copy] autorelease]; }
2) the setter may not retain the instance variable. one of several possibilities:
- (void)setA:(NSObject *)arg
{
...
a = [arg copy];
...
}
3) you end up with memory management implementation throughout your program, which makes it difficult to maintain. the semantics of the class (and how it handles instance variables' ref counting) should be kept to the class, and follow conventions for expected results:
- (void)stuff:(NSString *)arg
{
const bool TheRightWay = false;
if (TheRightWay) {
NSMutableString * string = [arg mutableCopy];
[string appendString:#"2"];
self.a = string;
[string release];
// - or -
NSMutableString * string = [[arg mutableCopy] autorelase];
[string appendString:#"2"];
self.a = string;
}
else {
NSMutableString * string = [arg mutableCopy];
[string appendString:#"2"];
self.a = string;
[self.a release];
}
}
failing to follow these simple rules makes your code hard to maintain and debug and painful to extend.
so the short of it is that you want to make your program easy to maintain. calling release directly on a property requires you to know a lot of context of the inner workings of the class; that's obviously bad and misses strong ideals of good OOD.
it also expects the authors/subclassers/clients to know exactly how the class deviates from convention, which is silly and time consuming when issues arise and you have to relearn all the inner details when issues arise (they will at some point).
those are some trivial examples of how calling release on the result of a property introduces problems. many real world problems are much subtler and difficult to locate.

Assigning to self in Objective-C

I'm from the C++ world so the notion of assigning this makes me shudder:
this = new Object; // Gah!
But in Objective-C there is a similar keyword, self, for which this is perfectly acceptable:
self = [super init]; // wait, what?
A lot of sample Objective-C code uses the above line in init routines. My questions:
1) Why does assignment to self make sense (answers like "because the language allows it" don't count)
2) What happens if I don't assign self in my init routine? Am I putting my instance in some kind of jeopardy?
3) When the following if statement fails, what does it mean and what should I do to recover from it:
- (id) init
{
self = [super init];
if (self)
{
self.my_foo = 42;
}
return self;
}
This is a topic that is frequently challenged by newcomers:
Wil Shipley: self = [stupid init];
Matt Gallagher: What does it mean when you assign [super init] to self?
Apple documentation: Implementing Initializers
Cocoa-Dev: self = [super init] debate
Basically, it stems from the idea that a superclass may have over-ridden the designated initializer to return a different object than the one returned from +alloc. If you didn't assign the return value of super's initializer into self, then you could potentially be dealing with a partially initialized object (because the object that super initialized isn't the same object that you're initializing).
On the whole, it's pretty rare for super to return something different, but it does happen in a couple of cases.
In Objective-C, initializers have the option of returning nil on failure or returning a completely different object than the one the initializer was called on (NSArray always does this, for example). If you don't capture the return value of init, the method might be executing in the context of a deallocated object.
Some people disagree about whether you should do the whole assign-to-self rigamarole if you don't expect to get something else back from the superclass initializer, but it's generally considered to be good defensive coding.
And yes, it looks weird.
It is true that init may return nil, if the initialization fails. But this is not the primary reason why you should assign to self when you implement your own initializers.
It has been mentioned before, but it is needed to stress even harder: the instance returned from an initializer may not be the same instance as the one you sent in, in fact it may not even be of the same class!
Some classes use this as a standard, for example all initializer to NSString and NSArray will always return a new instance of a different class. Initializers to UIColor will frequently return a different instance of a specialized class.
And you yourself can happely implement something like this if you want:
-(id)initWithName:(NSString*)name;
{
if ([name isEqualToString:#"Elvis"]) {
[self release];
self = [[TheKing alloc] init];
} else if (self = [super init]){
self.name = name;
}
return self;
}
This allows you to break out the implementation of some special case into a separate class, without requiring the clients of your API to care or even know about it.
All the other points here are valid, but it's important for you to understand as well that self is an implicit parameter to every Objective-C method (objc_msgSend() passes it) and can be written to, just like any other method parameter. (Writing to explicit parameters is generally frowned upon, unless they are out parameters.)
Typically, this is only done in the -init method, for the reasons others have stated. It only has any effect because self is returned from the method and used in the assignment id obj = [[NSObject alloc] init]; It also affects the implicit resolution of ivars, because, for example, if myVar is an ivar of my class, then accessing it in a method causes it to be implicitly resolved to self->myVar.
I'm still new to Objective C, but this post helped me in understanding this.
To sum it up, most init calls return the same object that self is already initialized to. If there is an error, then init will return nil. Also, some objects such as singletons or unique objects (like NSNumber 0) will return a different object than the one initialized (the singleton or a global 0 object). In these situations you need to have self reference that object. I'm by no means an expert in what is going on behind the scenes here, but it makes sense on the surface, to me.
If [super init] returns nil that means that you have been deallocated and your self parameter is now an invalid pointer. By blindly following the self = [super init] convention you will save you from potentially nasty bugs.
Consider the following non-typical initializer:
- (id)initWithParam:(id)param {
if (!param) {
// Bad param. Abort
self = [super init]; // What if [super init] returns nil?
[self release];
return nil;
}
else
{
// initialize with param.
...
}
}
Now what happens if my superclass decides to abort and return nil? I have been de-allocated and my self parameter is now invalid and [self release] will crash. By re-assigning self, I avoid that crash.