Why to use [super init] in Objective C constructors? - objective-c

Say I have a class named Item. Which is a superclass of NewsItem and TwitterItem.
If I want to create some NewsItem's do I have to use (inside constructor)
self = [super init];
If yes, why? In Java/C# I would just do,
NewsItem n = new NewsItem();
I don't have to do anything with superclasses in Java/C#. Just can't grasp it.

In Java and C#, the compiler automatically makes your constructor call the superclass constructor if you don't explicitly call it. For example, the “Java Tutorials” say this:
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
In Objective-C, the compiler doesn't do it automatically, so you have to do it yourself.

Because your superclass (and your superclass's superclass) need a chance to initialize, too.
And, keep in mind, that your superclass will [rarely] return nil or a different instance.
Which is why you do:
- (id)init
{
self = [super init];
if (self) {
... init stuff ....
}
return self;
}

Because you are overriding the init message. If you don't override it then [[NewsItem alloc] init] would just call the superclass' init message. In C#, you might use base to do the same.

since your custom object will at least inherit from the mothers of all Objects: NSObject, you have to call '[super init];'
'super' simply does call the init Method of its superclass

Related

Is not calling [super init] in the init method ever correct?

In Microsoft's WinObjC UIApplication.mm file (at https://github.com/Microsoft/WinObjC/blob/master/Frameworks/UIKit/UIApplication.mm) the init method is implemented for both UIApplication and WOCDisplayMode.
Neither class' init method calls [super init], or any method from that family of methods that would eventually result in a call to [super init]. I've never seen this before, apart from the initialization of NSProxy objects.
I've reproduced the implementation as of this writing of WOCDisplayMode below for reference.
-(instancetype) init
{
_fixedWidth = 320.0f;
_fixedHeight = 480.0f;
_fixedAspectRatio = 0.0f;
_magnification = 1.0f;
_autoMagnification = TRUE;
_sizeUIWindowToFit = TRUE;
_operationMode = WOCOperationModePhone;
return self;
}
It seems to me that this could create a number of problems; for example, if one of the superclasses of UIApplication, like UIResponder, at some point overrode init itself, and set up internal state that future method calls depended on.
Why might the implementor have elected not to call [super init]? Is this ever a justifiable decision? Is it ever the correct one?
This definitely seems like an error on behalf of the author(s) of those classes.
NSProxy does not call [super init] because it is an abstract superclass and does not inherit from NSObject.
Since their implementation of UIApplication inherits from UIResponder, and WOCDisplayMode inherits from NSObject they should be calling [super init] in these classes.
According to the documentation on Object Initialization:
The requirement to invoke the superclass’s initializer as the first
action is important. Recall that an object encapsulates not only the
instance variables defined by its class but the instance variables
defined by all of its ancestor classes. By invoking the initializer of
super first, you help to ensure that the instance variables defined by
classes up the inheritance chain are initialized first. The immediate
superclass, in its initializer, invokes the initializer of its
superclass, which invokes the main init... method of its superclass,
and so on (see Figure 6-1). The proper order of initialization is
critical because the later initializations of subclasses may depend on
superclass-defined instance variables being initialized to reasonable
values.
I would recommend logging it as an issue on the project.

The use of [[self alloc] init] when writing factory methods

I'm having trouble understanding the use of [[self alloc] init] when writing factory methods. I understand that factory methods are convenience methods to create instances of a class, and that they do the alloc, init, and autorelease for you. I can see how this is formed, for example in the declaration of an NSArray property with the factory method arrayWithArray:, or array, etc. called on it to set it up.
I can obviously see how this is different to an outright (explicit) call to alloc and init.
My issue with this is that I don't understand factory methods at a deeper level. I came across an explanation online that said instead of calling alloc and init explicitly, a class factory method could be used to basically encapsulate something like this:
+(instancetype)createWithString:(NSString *)string
{
return [[self alloc] initWithString:string];
}
But how do instancetype and [self alloc] effectively allow for subclasses to make use of the class factory method?
instancetype is a keyword that says "the return type of this method is the type of the class that this method was called on" (or a subclass). So, if you call [Baseclass createWithString:], the return type is Baseclass *. However, let's say you create a subclass that does not override this method. If you call [Subclass createWithString:], the return type is Subclass * (not Baseclass *).
When a class receives a message, self points to the Class object. So when calling [Baseclass createWithString:], self will point to the Baseclass object. However, when calling [Subclass createWithString:], self will point to Subclass instead, so if Subclass defines its own alloc or initWithString: methods (that is, it overrides them) its versions will be called instead.

Call Superclass method

In Objective-C, how do I call an object's super class method?
For example, lets say I have an instance of an object "foo".
"foo" has a method that is overriden. I do not want to call this overriden method. Instead, I want to call the original method on the foo object instance.
You cannot do:
[[instance super] super_method]; as far as I am aware. So how can I go about doing this?
I know I can add a method to foo:
-(void) callsuper
{
[super super_method];
}
and do:
[foo callsuper];
Any other ways? I really don't want to create a method just to do that.
The keyword super does this for you. It is seen very commonly in -init methods. Here is an example.
- (id)init {
if (self = [super init]) {
// custom initialization
}
return self;
}
In this case, the super keyword is used to call this class' superclass implementation of the -init method. super can be used on any method that your superclass implements.

super bound statically at compile time?

I want to create a class cluster with a base class and 2 subclasses. Creating an instance of the base class should return a subclass based on some conditions, but creating a subclass directly should create it. I wrote the following code in the base class:
+ (id)allocWithZone:(NSZone *)zone {
// prevent infinite recursion
if ([self isEqual:Base.class]) {
// if self is the base class, return a correct subclass
if (somecondition) {
return [SubclassA alloc];
}
return [SubclassB alloc];
}
// otherwise, alloc is called on a subclass
// call NSObject's alloc
return [super allocWithZone:zone];
}
and it works, but I'm really surprised that it does. Namely, when invoked on a subclass, why does super evaluate to the Base class's superclass (NSObject), and not the Base class (because invoked on SubclassA, the superclass is Base)? It is as if the allocWithZone: method call, inherited from Base, just always evaluated super relative to Base, not the real runtime class of the caller. I think similar code in Java and other OO languages would not work and result in infinite recursion, would it? Is this code wrong?
Your code is correct. [super ...] always uses the superclass of the class implementing the method. In your code, +allocWithZone: is implemented by class Base, so [super allocWithZone:zone] uses Base's superclass when searching for the next +allocWithZone: implementation to call.

Creating a class with no init method (Objective-c)

Is it possible to create a class with no init method so as to force all callers to create the object with a factory method instead?
So basically, you want to make sure that your class is never initialized using -init, right? You can't do exactly what you want to do, but you can come close.
Since you inherit from NSObject, you have an init method and there's nothing you can do to prevent it from being called. That said, you could override init to this:
- (id)init
{
[self dealloc];
#throw [NSException exceptionWithName:#"MyExceptionName" reason:#"Reason" userInfo:nil];
return nil;
}
This way, anytime someone calls your -init method, it kills the object, so practically speaking, your init method is pretty much un-callable.
If you really wanted to cause trouble for users of your class who use init, you can do:
#implementation MyClass
- (id) init
{
// Still have to make sure the runtime has initialised everything for "self"
self = [super init];
if (!self) return nil;
[self release]; // some say you should use [super dealloc]
[super doesNotRecognizeSelector:_cmd];
return nil;
}
#end
You invoke super's doesNotRecognizeSelector: because you might want to implement your own behaviour for unrecognised selectors for your class.
Depends. If you have your class inherit from NSObject, it will have the inherited init method (which does nothing to your instance variables). So in that sense, even if you really really wanted to not have an init method, you'd most likely still have one. So if your question was "Do I need to implement a trivial init method?", the answer is "no, you don't need to". However, if your question was "Do I need to call the init method if I didn't override it?", then the answer is "yes, you do". Whatever you do with NSObject subclasses, at some point you still need to call init after the object is created. Such is the way of life.
That being said, you most likely want an init method, unless your object initialization requires nothing more than zeroing your whole object.
Otherwise, if you choose to not inherit from NSObject or any of its subclasses and just inherit from nothing, which is clearly a bad idea because of how the NSObject class deals with everything the ObjC runtime needs to do and the requirements are quite high, then you'll potentially end up with no init method at all. But seriously, don't try this at home.
Sure. In Objective-C, there are no actual constructors. init-type methods are typically used to initialize a class, in the same vein as a constructor, but they're just a "normal" method (there's nothing special about them like there are with, e.g., Java constructors).
That said, unless your class does no initialization for its instances, you probably want to have some sort of init method.
NSObject implements an init method for you that does whatever it does. If your class has nothing to setup when it's instantiated then simply do not override the -(id)init method provided by NSObject. But you still call it when you create the instance.