Does Calling -init on super Chew Up Memory - objective-c

The following is commonplace in Objective-C.
- (id)init {
if (self = [super init]) {
// custom initialization
}
return self;
}
Because -init is an instance method, it must be called on a valid instance of a class, and an instance of a class must be instantiated. This instantiation uses up memory. Does calling -init on super use memory as it has to instantiate a new object to call the init method on?

Does calling -init on super use memory as it has to instantiate a new object to call the init method on?
No, because your premise is false. super, as the receiver of a message, is the same object as self; it's just a signal to the compiler to use objc_msgSendSuper() instead of objc_msgSend(). The former starts method lookup with the superclass, but the instance that runs the method is still the same.
No new instance is created by using the super keyword.

It all depends on what's going on up the chain.
If it's simply "[NSObject init]", then nothing (obvious) is happening.
But if it's "[BrianTracySuperAwesomeBaseClass init]" with a lot of initialization and setting up various ivars and properties, then yes, you're using a bit of memory.
In general, you shouldn't load down your "init" methods with lots of stuff going on... instead you should rely on lazy loading or allocate-on-demand things for your Objective C objects.

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.

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.

Recommended instance variables initialization place for Cocoa Touch classes

I'm feeling very stupid, but...what is the right way to init instance variables in custom types, derived from Cocoa Touch UI classes?
Say I have type, derived from UIViewController, let it be TRUIController.
I defined an ivar as follows:
#implementation TRUIController
{
NSNumberFormatter *_numberFormatter;
}
#end
And where should I put _numberFormatter initialization code, if I want it to be executed before any UI methods like viewDidLoad, etc?
In other languages I would create constructor, call base constructor and then init my ivars.
But that simply does not work in objective-c and Cocoa Touch.
In case described above,
If I write
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibBundleOrNil bundle:nibBundleOrNil];
if(self)
{
//init ivars
}
return self;
}
It won't work, I'll try other initWithBlaBla methods, and finally find init, which is actually called, in that case - initWithCoder:
Now, let's say I have class, derived from UITableViewCell. Again, need to init NSNumberFormatter ivar. Why can't I just override init:, call super and init my ivars?
What's the idea behind this strange design decision not to have single common initialization method for all types?
Is it the only way to initialize ivars in derived types? Every time do some research to figure out what method to override this time?
Have I missed something? Because it feels extremely stupid/unintuitive/error-prone
You have to do so overriding the designated initializer.
From the official documentation
A designated initializer is an init method of a class that invokes an
init method of the superclass. (Other initializers invoke the init
methods defined by the class.) Every public class should have one or
more designated initializers. As examples of designated initializers
there is NSView’s initWithFrame: and NSResponder’s init method. Where
init methods are not meant to be overridden, as is the case with
NSString and other abstract classes fronting class clusters, the
subclass is expected to implement its own.
Designated initializers should be clearly identified because this
information is important to those who want to subclass your class. A
subclass can just override the designated initializer and all other
initializers will work as designed.
When you implement a class of a framework, you often have to implement
its archiving methods as well: initWithCoder: and encodeWithCoder:. Be
careful not to do things in the initialization code path that doesn’t
happen when the object is unarchived. A good way to achieve this is to
call a common routine from your designated initializers and
initWithCoder: (which is a designated initializer itself) if your
class implements archiving.
Read the documentation for finding out which initializer is the designated one and override it.
According to the documentation of UIViewController initWithNibName:bundle: is the designated initializer for this class is so you should override that one, but if you are not programmatically instantiating your class (e.g. you're loading it from nib/storyboard) you have to override the archiving method initWithCoder:.
As suggested by the documentation you can create a routine for initialization and call it from both the designated initializer and the archiving method.
It generally makes sense to use the designated initializer as a starting point, but if you are not sure this is always the one that will be used that won't make all that much sense.
Personally I therefore prefer to create a setup method which is called from any init-method I know is likely to be used at some stage. For ViewControllers I normally call the setup method from viewDidLoad instead (unless of course there's any state that's needed before this stage).

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

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

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.