Can someone explain to me what init and alloc do in Obj-C. I am reading this obj-c book that gives an example of creating object but it does not really go into details of what it does. What does alloc return? what does init return?
Animal * k = [Animal alloc];
k = [k init];
alloc allocates a chunk of memory to hold the object, and returns the pointer.
MyClass* myObj = [MyClass alloc];
myObj cannot be used yet, because its internal state is not correctly setup. So, don't write a code like this.
init sets up the initial condition of the object and returns it. Note that what's returned by [a init] might be different from a. That explains the code Yannick wrote:
-init{
self=[super init]; // 1.
if(self){ // 2.
....
}
return self; // 3.
}
First, you need to call the superclass's init, to setup the superclass's instance variables, etc. That might return something not equal to the original self, so you need to assign what's returned to self.
If self is non-nil, it means the part controlled by the superclass is correctly initialized. Now you perform your initialization. All of the instance variables are set to nil (if it's object) and 0 if it's integer. You'll need to perform additional initial settings.
Return the set-up self. The returned self might be different from what's allocated! So, you need to assign the result of init to your variable.
This suggestions an important lesson: never split the call to alloc and init. Don't write:
MyClass* myObj = [MyClass alloc];
[myObj init];
because [myObj init] might return something else. Don't try to get around this by writing:
MyClass* myObj = [MyClass alloc];
myObj=[myObj init];
because you will eventually forget to write the part myObj= in the second line.
Always write:
MyClass* myObj = [[MyClass alloc] init];
I also don't recommend writing:
MyClass* myObj = [MyClass new];
because it does not correctly call the initialization method: some classes doesn't accept a plain init. For example, NSView needs initWithFrame:, which can't be called with new. So, don't use new either.
In its simplest form:
alloc: short for allocation, reservers a memory location and returns the pointer to that memory location. This pointer is then stored in the k variable.
init: short for initialization, sets up the object and returns the object. The init method depends on the object, but it generally involves sending the init message to the superclass. And if that init method (of the superclass) returns an object (not nil) some ivars may be set up depending on the task of that class.
--
Example of an init implementation, the Schedule class initializes its channels ivar with an empty array. Basically your giving the Schedule object a chance to sort itself out, so it can start receiving messages once it is created. You could remove the channels initialization from the init method, but then you would have to check if the channels ivar is nil in every method of the Schedule class and initialize it if it is indeed nil.
- (Schedule*)init {
self = [super init];
if (self) {
channels = [[NSMutableArray alloc] initWithCapacity:0];
}
return self;
}
alloc and init are two methods that are inherited from NSObject
you can provide your own methods or call the ones from NSObject
alloc allocates the memory to create a new instance of your class(#interface)
init initializes the contents of that instance, by default init sets all member values to 0/nil however you can create your own init method to customize what is done.
Animal * k = [[Animal alloc] init]; // creates a new Animal object
you can also write
Animal * k = [Animal new]; // which would be a bit more similar to other languages
The NSObject root class provides a class method, alloc,
alloc: reservers a memory location and returns the pointer to that memory location.
The alloc method has one other important task, which is to clear out the memory allocated for the object’s properties by setting them to zero.
This avoids the usual problem of memory containing garbage from whatever was stored before, but is
not enough to initialize an object completely.
You need to combine a call to alloc with a call to init, another NSObject method:
(id)init;
The init method is used by a class to make sure its properties have suitable initial values at creation.
The correct way to allocate and initialize an object is to nest the alloc call inside the call to init, like this:
ClassName *objectName = [ClassName alloc] init];
from: apple documents
Alloc will allocate the memory for the object, but Init puts the object into the memory and sets the default values.
Related
If I have an NSObject subclass which either has no -init method or simply does nothing in -init, is there any difference between an instance created these two ways:
MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];
By "does nothing in -init" I mean
- (id)init {
self = [super init];
if (self) {
}
return self;
}
Since NSObject's -init method itself does nothing, I can't see there being any difference, but of course the advice is that you must call -init to properly prepare an object.
Here's the snippet from NSObject's -init method which got me wondering about this:
The init method defined in the NSObject class does no initialization; it simply returns self.
If I have an NSObject subclass which either has no -init method or
simply does nothing in -init, is there any difference between an
instance created these two ways:
MyClass *instance = [MyClass alloc];
MyClass *instance = [[MyClass alloc] init];
Technically, there is no difference.
But that doesn't mean you should use a bare +alloc to ever create an instance for a variety of reasons.
First, it is the principal of the thing. Objective-C coding standards say +alloc should always be followed by -init.
Secondly, it is all about consistency and code maintenance. What happens when you refactor MyClass to be a subclass of some class where the designated initializer is actually critical? A nasty, hard to figure out, bug is what happens.
Of relevance, note that the use of +new has been all but deprecated for a similar reason. It makes refactoring tedious (dammit! gotta break apart THIS call site, too!) and the convenience factor is exceedingly minimal.
No, it's not and you're not doing nothing, you're calling [super init] and that does a lot to initialize your superclasses up until NSObject.
You can do it in theory.
When you want to create an instance, you can do it simply using the alloc method, so this code is perfectly accepted:
NSObject *someObject = [NSObject alloc];
What creates the instance is the alloc method, so you have created an instance of NSObject.
But if you want to use it you have to initialize it, since the NSObject init method is used by a class to make sure its properties have suitable initial values at creation (Apple documentation).
The most important thing done by the init method is to create the self variable, so if you want to use the instance created with the alloc method, you have to init it.
- (id)init {
self = [super init];
if (self) {
// initialize instance variables here
}
return self;
}
Without the initialization method you have only an unusable instance.
alloc allocates a place in memory for the instance of the object to be stored. If you’re using a local variable it is allocated on the stack, while objects (ivars etc) are allocated on the heap.
init initialises the instance of the object and points it to the allocated memory space - this is why you must always call init after alloc.
e.g.
MyClass *instance = [[MyClass alloc] init];
In your instance your init implementation is empty so it can be removed and you can let the superclass handle it. You would override init to set some state on the object itself.
You might want to take some time to read the Apple Documentation on this if you want to brush up.
Calling MyClass *instance = [MyClass alloc]; - will leave you with an invalid object. You need to allocate and initialize every object you create.
If you do it this way, all objects until MYClass will be initialised. MyClass won't though.
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.
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).
If self is able to store the base class instance then when we are returning the self, how it transformed to derived instance.
Here's what I think you're asking: suppose we have a base class Base and a subclass Derived. If -[Derived init] calls -[Base init] and -[Base init] returns a different instance, won't that different instance be an instance of Base and not Derived and thus inappropriate? For example, the new object won't have the instance variables that Derived might have added to the class.
The answer is that Base is not allowed to do that. If it replaces the original instance, it must do so in a manner that respects the dynamic type of that original instance. For example, it might do something like:
// Re-allocate with 100 extra bytes
id newSelf = NSAllocateObject([self class], 100, [self zone]);
[self release];
self = newSelf;
// ... continue to initialize ...
return self;
Or, it might dynamically generate a new subclass of the original class and then allocate a new instance of that new class.
NSString* newClassName = [NSString stringWithFormat:"%#_DynamicSubclass", NSStringFromClass([self class])];
Class newClass = objc_allocateClassPair([self class], [newClassName UTF8String], 0);
// ... further configure the new class, by adding instance variables or methods ...
objc_registerClassPair(newClass);
id newSelf = [newClass alloc];
[self release];
self = newSelf;
// ... continue to initialize ...
return self;
Whatever it does, it has to satisfy the constraint that the new instance is suitable to be used wherever the old instance was, based on its dynamic type.
self is a hidden method argument:
// this Objective-C
- (id) initWithString:(NSString*)str;
// gets implemented like this C function would be
- (objc_object*) Foo_initWithString(Foo* self, SEL _cmd, NSString* str);
It is a pointer to memory (allocated with alloc) that is already big enough to hold the most derived object. The most derived class calls super's init, which also calls its super's init and so each class in hierarchy gets its constructor called.
So, nothing is transformed — it is just a pointer to an already existing object, you can either return it (99.9% of the time) or substitute another object instead.
Note there is a second hidden argument, the selector _cmd, which in this case equals to #selector(initWithString:). You can also use it if you need current method name e.g. for debug logging.
Here super instance is not assigned to derived instance. self = [super init]; is simply like telling the runtime system to look for the init method to the super class method selector table... inside super -init method, the self is like support for both super class and derived class. In objective c, incase of class inheritance.. only instance variables are duplicated.. methods are shared by all classes in hierarchy. If u override.. u should do self = [super init]; this will lead u to NSObject -init method. If we override -init... methods from super class, make sure that the super -init... is called first. This is what i understand. Thank you.
Is it safe to reinitialise self within a class method?
MyClass * a = [[MyClass alloc]init];
#implementation MyClass
{
-(id)init
{
if(self = [super init])
{
...
}
return self;
}
-(void)redefine
{
//??
self = [self init];
}
}
will a point to the reinitialized instance of MyClass?
Thank You,
nonono
Provided that (a) your class and its superclasses can be re-init'ed without leaking memory or resources and (b) you know that your class and its superclasses inits all return the self they are passed and not a reference to some other object, then yes...
Otherwise things will go wrong. Consider your redefine method; in the body of this method self is just a local variable whose contents is initialized to point to some object. Changing the value in that local variable does not change the object it originally pointed at, or the value of any other variables which point to that object. E.g. consider the variation:
#implementation Q
{
- (void) redefine
{
self = [[Q alloc] init]; // changes the *local* self to refer to a new object
}
...
}
...
Q *someQ = [[Q alloc] init]; // allocate an object
[someQ redefine]; // NO effect on someQ, another Q is just created and leaked
Clearly this does not alter someQ, and your version may not either. Your code will have the effect you wish if and only if you know init always returns the object it was passed - which is not guaranteed in Obj-C.
As long as init returns self, which it normally does, nothing will go wrong.
But you probably want to split your initialization to some separate method, which you can call from both init and redefine.
You need to return your new object from -init, not simply assign a new value to self. And you must remember to release the old self, since it was created with +alloc. Caveats aside though, returning a different object from -init is explicitly allowed. That's why you'll see newbies being corrected when they write something like this:
// Bad example! Do NOT do this!
Foo *foo = [Foo alloc];
[foo init];
This is an anti-pattern because -init is not required to return the same object it was called on. That means the above can end up assigning foo to point to an object that's been released, instead of to the object that was initialized in its place. This is why you always see +alloc and `init chained together like so:
Foo *foo = [[Foo alloc] init];
It's also why you need to reassign self when calling super's -init, because it may also have returned a different object.
self = [super init];