Objective-c - what does [super init] return? - objective-c

New to objective-c. Wrote a code-snippet to better understand the init mechanism, and ended up with a few questions.
#implementation MyClass
-(id) init
{
if (self) {
i = 5;
NSLog(#"self before init - %# %p i=%d",[self className], &self, i);
} else {
NSLog(#"self is null???");
}
id someClass = [super init];
NSLog(#"the result of super-init - %# %p",[someClass className], &someClass);
self = [super init];
if (self) {
NSLog(#"self after init - %# %p %d",[self className], &self, i);
} else {
NSLog(#"self is null???");
}
return self;
}
i is a private instance variable int.
Here is the result:
2012-12-14 18:01:26.403 Init[1621:303] self before init - MyClass 0x7fff5fbff848 i=5
2012-12-14 18:01:26.405 Init[1621:303] the result of super-init - MyClass 0x7fff5fbff838
2012-12-14 18:01:26.405 Init[1621:303] self after init - MyClass 0x7fff5fbff848 5
What really surprised me is that that someClass's class Name is MyClass.
How does NSObject know to return the sub-classes instance (not just the type match, it is the exact same object)?
I'm aware that it is not good form to call init many times, and initialize instance variables before calling init but I was just experimenting.
Thanks.

You do need to use the standard schemen (more or less):
-(id)init {
self = [super init];
if (self) {
// Do initialization stuff
}
}
Your class subclasses some other class. The call to super init runs the init routine of your superclass. Without it your class is not properly initialized and may malfunction strangely. (However, it's probably not wise to call super init twice, as this could have bad side-effects.)
There are cases where you would not call super init, but would instead call a version of init in your own class. Basically, if you have initWithJunk: and init, you can have initWithJunk: call [self init] instead of [super init] so that the stuff that self init would do gets done and doesn't have to be reproduced in initWithJunk:.
This is especially critical if you write a "category" that adds an init... method to an existing class -- you must call some version of [self init] to assure that the base class's initializer runs.
Understand that the super init method is not (usually) replacing the existing instance with a new one, but rather is initializing instance fields in it that belong to the superclass. The reason for receiving the "self" value back from the super init call is two-fold:
The init routine can return a nil in the event that some sort of error occurs.
In some (rare) special cases the init routine may replace the supplied instance with a different one (eg, a cached version).

Related

Designated initializer should only invoke a designated initializer on 'super'

This code is a modified version of Ordered Dictionary implemented here.
https://github.com/nicklockwood/OrderedDictionary/tree/master/OrderedDictionary
Interface -> OrderedDictionary.h
#interface OrderedDictionary : NSMutableDictionary
{
}
Implementation -> OrderedDictionary.m
// This is the new method added.
- (instancetype)init
{
return [self initWithCapacity:0];
}
- (instancetype)initWithCapacity:(NSUInteger)capacity
{
self = [super init];
if (self != nil)
{
// Allocate here.
}
return self;
}
The code works fine but I get following warnings in "- (instancetype)init".
Designated initializer should only invoke a designated initializer
on 'super'
Designated initializer missing a 'super' call to a
designated initializer of the super class
What am I doing wrong and how do I fix it?
Made following changes to the code to fix the problem
// This is the new method added.
- (instancetype)init
{
self = [super init];
if (self != nil)
{
// Allocate here.
}
return self;
}
- (instancetype)initWithCapacity:(NSUInteger)capacity
{
self = [super initWithCapacity:capacity];
if (self != nil)
{
// Allocate here.
}
return self;
}
try adding
- (instancetype)initWithCapacity:(NSUInteger)capacity NS_DESIGNATED_INITIALIZER;
To the #interface block. All initialization paths should flow through the designated initializer - in your case initWithCapacity: is the obvious choice since init calls it. You may still run into problems, the designated initializer must call the super class's designated initializer. If the super class defines designated initializers those must be implement by your class as well...
In general subclassing NSMutableDictionary is considered bad practice because NSMutableDictionary is the public facing piece of a class cluster. This may be part of the cause of the compiler warnings.
As you can read in NSMutableDictionary documentation, there are two designated initializer for this class:
initWithCapacity: Designated Initializer
init Designated Initializer
Here you are calling from initWithCapacity in your class to super.init. That's the reason the compiler warns you.
This code maybe is better:
// This is the new method added.
- (instancetype)init
{
return [self initWithCapacity:0];
}
- (instancetype)initWithCapacity:(NSUInteger)capacity
{
self = [super initWithCapacity:capacity];
if (self != nil)
{
// Allocate here.
}
return self;
}
I'd bet some of you are tripping over this warning message when you have Xcode convert your code to "Modern Objective-C Syntax."
I've seen cases where Objective-C header files have been modified by the converter to have two designated initializers:
- (instancetype) init NS_DESIGNATED_INITIALIZER; // DO NOT USE
- (instancetype) initWithFileset: (NSArray *) fileset NS_DESIGNATED_INITIALIZER; // use this to instantiate
If you modify this code to a single initializer, you may find the warning message goes away:
- (instancetype) init; // DO NOT USE
- (instancetype) initWithFileset: (NSArray *) fileset NS_DESIGNATED_INITIALIZER; // use this to instantiate
In short, check the header and the source file when you see this warning message.
You should only call the super of your own function.
So replace
self = [super init];
with
self = [super initWithCapacity:capacity];

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;
}

How to initialize a NSMutableArray in Objective C?

I come from a Java background and I am learning Objective C. I am trying to create a class that has a string array and a member function to modify the Array. My code looked like this:
#implementation TAWChapter
#synthesize mSubject;
#synthesize mItems;
- (id) init{
self.mItems = [[NSMutableArray alloc] init];
return self;
}
- (void) setSubject:(NSString *)subject{
self.mSubject = subject;
}
- (void) addItem:(NSString *)item{
[self.mItems addObject:#"asdf"];
}
#end
Which didn't work. I got a "[__NSArrayI addObject:]: unrecognized selector sent to instance " and a "NSInvalidArgumentException". After searching on internet, I changed the single line in the constructor to:
self.mItems = [self.mItems init];
It worked, but why? From a Java developer's point of view the first one makes more sense than the second one. And I have another line it's the same as the first one but it's working(not in a constructor). Can someone explain this to me please?
First of all, you should adhere to Objective-C coding conventions. In Objective-C, classes don't have constructors, they have initialisers. In Objective-C, initialisers invoke the initialiser of the superclass, so it should look like this:
- init
{
self = [super init];
if (!self) return nil;
// set up other stuff here
return self;
}
Second, unless you are using ARC, you might have a memory leak. The first line of your initialiser assigns an object that you own to a property that also likely takes ownership. You should use either:
// property takes care of ownership
self.mItems = [NSMutableArray array];
or:
// assign to instance variable directly with owned object
mItems = [[NSMutableArray alloc] init];
Apple sometimes discourage the use of accessor methods in initialisers because it can fiddle with things like KVO, but consistent use of accessor methods ensures proper object ownership and memory management.
By changing your line in your initialiser to:
self.mItems = [self.mItems init];
does nothing. When your initialiser method is called (which is typically just after it has been allocated), all instance variables are automatically set to nil. So what you are doing is just:
self.mItems = [nil init];
which is just:
self.mItems = nil;
and, don't use init without first allocating an instance, and never use init more than once.
If you do not let the superclass initialise itself, then it may manifest as problems in other areas. Do a Build & Analyze and ensure you have fixed up any issues pointed out by the analyser.
Since objective-c is a superset of c, it's basically c with some "OO" syntax sugar. Before you can create (or use!) an object, you must alloc space for it in the heap. you do this with [Class alloc]. The next step is the initialization of that space. alloc returns a pointer to that space in the heap, which you initialize with init ;)
So you call Class *myObjc = [[Class alloc] init];.
If you use inheritance (which you do since you inherit from NSOBject), you must make sure that your superclass initialized everything properly, thats the call to super. To make sure you don't get a runtime error, check for self != nil, which you do implicitly with if(self)
self.mItems = [self.mItems init]; // doesn't do anything, since you call the getter for mItems with self.mItems and try to init. then you try to set mItmes to itself.
use this code:
#implementation TAWChapter
#synthesize mSubject, mItems;
- (id)init
{
self = [super init];
if (self) {
mItems = [[NSMutableArray alloc] init];
}
return self;
}
- (void) setSubject:(NSString *)subject{
mSubject = subject;
}
- (void) addItem:(NSString *)item{
[mItems addObject:item];
}
#end
You should call super and assign its result to self in your init method:
- (id)init
{
self = [super init];
if (self) {
self.mItems = [[NSMutableArray alloc] init];
}
return self;
}
The another way could be creating NSMutableArray from NSArray:
NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];

Super in initializing objects [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
why does initializing subclasses require calling the super class's same init function?
I really can't understand the role of super in initializing an object.
For example, having this (example — not written by me) code:
#implementation MyObject
- (id) init
{
if([super init]){
return self;
} else {
return nil;
}
}
#end
What [super init] actually does? I'm confused, can't get the point
It is necessary to ensure correct initialisation of inherited instance variables from the super class of MyObject.
Since Objective-C is object oriented you can inherit from other classes. When you inherit from other classes you can intercept messages and get to decide if you pass them on to the class you inherit from. In the case of init it is almost always important to do self = [super init] or use the designated init method of the class to make sure the object is created correctly. Imagine if in MyObject in your init method you create an NSMutableArray that your class uses but init was never called because someone else inherited from your class and never called [super init]. You would then have nil references or either a bad pointer every where you attempted to used your NSMutableArray. The reason why it is important to set self equal to [super init] is the value of self may change such as in error recovery.
//this is valid
-(id)init
{
if((self = [super init]))
{
if(someInitializationFails)
{
[self release];
self = nil;
}
}
return self;
}
Wil Shipley recommends this (from 2009):
- (id)init;
{
if (!(self = [super init]))
return nil;
// other stuff
return self;
}
But why assign super init's return to self?
Matt Gallagher's article attempts to explain it...
-- Quote:
If you remember back at the start, I
said that the initWithString: part of
a typical [[MyClass alloc]
initWithString:#"someString"]
invocation is converted into an
objc_msgSend call:
MyClass *myObject2 = objc_msgSend(myObject1, initSelector, #"someString");
So by the time we get
to the inside of the method, self
already has a value; its value is
myObject1 (i.e. the allocated object,
as returned from the [MyClass alloc]
call. This is essential because
without it, the super invocation
wouldn't be possible — the self value
is used by the compiler to send the
invocation:
[super init];
becomes:
objc_msgSendSuper(self, #selector(init));
Yes, self already
has a value when your initializer
starts. In fact, it is almost
guaranteed to be the correct, final
value.
-- Unquote
Essentially, I think a lot of people are left confused as to what each init method's 'self' is pointing to exactly, up through the superclass chain.
The answer to this riddle is implied in Apple's Objective-C Programming Language doc, under the section titled Designated Initializers:
Note that B version of init sends a
message to self to invoke the
initWithName: method. Therefore, when
the receiver is an instance of the B
class, it invokes the B version of
initWithName:, and when the receiver
is an instance of the C class, it
invokes the C version.
Or, in other words, the 'self' variable points to the our instance that is being initialized. Again to reemphasize, all of these init methods up through the superclass chain are inherited by our instance, and as such, the 'self' variable in them points to our instance (unless explicitly changed) .
Am I right? Of course!

Objective C init

Disclaimer, I'm new to Objective C. But I can't find this explained. I've seen two ways of implementing init:
- (id)init {
if ([super init]) {
return self;
} else {
return nil;
}
}
and
- (id)init {
if (self = [super init]) {
// do your init business here
}
return self;
}
so let's say i have:
myObj = [[MyObject alloc] init];
where MyObject class is a subclass of NSObject. in the second example, does init not return an initialized version of NSObject? so myObj would ... how would it know what it is? wouldn't it think it was an NSObject rather than a MyObject?
1) First version is just wrong. self should be always assigned with value returned by super initializer, because init<...> of super can return another object upon initialization (it's not unusual BTW). Second version is actually an 'official' way to implement init<...> methods.
2) 'wouldn't it think it was an NSObject rather than a MyObject'. myObj is instance of 'NSObject' and instance of 'MyObject'. It's the whole point of inheritance.
i just want to know, under the hood, how it does it.
It's pretty simple. 99.9% of all the classes you'll ever write will inherit from NSObject in some fashion. In the initializers, you're supposed to invoke super's designated initializer and assign it to self. Eventually, [super init] will be invoking -[NSObject init]. According to the documentation, that's implemented like this:
- (id)init {
return self;
}
So technically, if you inherit directly from NSObject, you're probably safe to not do the assignation of self = [super init];, because you know (and you're guaranteed) that this is equivalent to: self = self;, which is kind of pointless. Regardless, you should leave it in for consistency's sake.
However, once you start getting further down the inheritance chain, and especially when you're inheriting from opaque classes (ie, a class whose .m file you do not have), then things start getting shady. It is possible that you'll come across a class whose designated initializer looks something like this:
- (id) initWithFoo:(id)aFoo {
if ([aFoo isSuperFast]) {
[self release];
return [[SuperFastFooWrapper alloc] initWithFoo:aFoo];
}
self = [super init];
if (self) {
_foo = [aFoo retain];
}
}
This isn't as common, but it does happen. In this case, we're destroying self ([self release], to balance the alloc call that immediately preceded this) and instead returning a different object.