I'm trying to find the difference between init and constructor in Objective C.I'm not a C developer, but I need to convert some Objective C-code to Java and actually I can't understand the difference between both things.
In Objective-C, the way an object comes to life is split into two parts: allocation and initialization.
You first allocate memory for your object, which gets filled with zeros (except for some Objective-C internal stuff about which you don't need to care):
myUninitializedObjectPointer = [MyClass alloc];
The next stage is initialization. This is done through a method that starts with init by convention. You should stick to this convention for various reasons (especially when using ARC), but from a language point of view there's no need to.
myObjectPointer = [myUnitializedObjectPointer init];
or in one line:
myObjectPointer = [[MyClass alloc] init];
In other languages these init methods are called constructors, but in Objective-C it is not enforced that the "constructor" is called when the object is allocated. It's your duty to call the appropriate init method. In languages like C++, C# and Java the allocation and initialization are so tightly coupled that you cannot allocate an object without also initializing it.
So in short: the init methods can be considered to be constructors, but only by naming convention and not language enforcement. To Objective-C, they're just normal methods.
Related
Is it really necessary to call init after object allocation? I mean: in Java for instance if you don't call it (the constructor), it will be called anyway (the default constructor). In Objective C you can create an alternative constructor (like Java) and one of the things I see the most is self = [super init]. I read: cocoawithlove article, but in the end it's not clear why we should make such assignment self = [super init]. It just says that the [super init] can return a different object, and then we must replace the self with that new object. That wouldn't explain why we do it in first place.
is it really necessary to call init after object allocation?
Yes, it is necessary. To compare to Java, calling [super init] (or some other designated initializer) effectively runs the superclass' constructor. This mechanism is provided for you in Java, but not in Objective-C. So it is not called implicitly in ObjC as it is in Java. In ObjC, you must call one of the superclass' designated initializers explicitly. If you do not call your superclass' initializer, your object will not be entirely initialized. This may result in no exhibited side-effects, or it could result in a completely unusable object which invokes undefined behavior.
why we should make such assignment self = [super init].
Right, alloc creates an allocation (with zeroed memory) and sets the pointer to the class information isa, but a superclass' initializer permits the superclass to exchange the instance with another which may be more appropriate. Typically, you would avoid doing this in your own subclasses. The other reason to perform this and the nil check is that it is the means an error is handled. In ObjC, exceptions are generally non-recoverable, so the conventional way to report an error to the subclass is to return nil. That is why it is also important not only to assign self, but also to test it for nil.
There is a big difference between Objective C and Java. Java is an interpreted language built from the ground up, while Objective C was built on top of C language. Anything that you can do in C is valid in Objective C as well.
Unlike Java, C (and by extension, Objective C) has "raw memory allocation". In Java, a call to new automatically calls the constructor. The language makes it impossible to go around this mechanism. In Objective C, however, you can allocate raw memory. The memory does not contain a ready-to-use object at the time it is returned to you from alloc - it is only partially prepared for use. The memory block has a reference count, and it provides enough space to fit your object, but it is not ready to receive messages that your own subclass has implemented. That is why you must call init (or use new, which combines alloc and init for you).
The if (self = [super init]) assignment/check lets you trap errors during the construction phase of your object. If your own initializer fails, you can set self = nil to report the problem up the chain. Assigning a different object is far less common, but it could be done as well.
After allocation instance variables should be instantiated.
self = [super init] refers to initialize the super class init method
A common mistake is to write
self = [[super alloc] init];
which returns an instance of the superclass, which is NOT what you want in a subclass constructor/init. You get back an object that does not respond to the subclass methods, which can be confusing, and generate confusing errors about not reponding to methods or identifiers not found, etc.
self = [super init]
is needed if the super class has members (variables or other objects) to initialize first before setting up the subclasses' members. Otherwise the objc runtime initializes them all to 0 or to nil. (unlike ANSI C, which often allocates chunks of memory without clearing them at all)
And yes, base class initialization can fail because of out-of-memory errors, missing components, resource acquisition failures, etc. so a check for nil is wise, and takes less than a few milliseconds.
As i was reading through the book on Objective-C, i came across an example that initialized a class as follows:
ClassName *p = [[ClassName alloc] init];
While it makes sense that first we need to allocate memory to store data ClassName has before initializing, the following works just as well:
ClassName *p = [ClassName alloc];
Is init always needed?
In theory, it's not technically required. That's because NSObject's init method is effectively just return self;. However, in practice, it's absolutely essential. Objects perform internal setup inside the init method - creating internal state, allocating private members, and generally getting ready for action. The init method may not even return the same object as you allocated.
Think of it in two phases: alloc allocates memory, but that's it - it's analogous to Java's new. init configures the state of the memory so that the object can perform it's tasks - analogous to Java calling the constructor. Don't leave it out!
Good question. And you're right. Strictly speacking "init" is not required.
"alloc" does three important things to create an object:
- allocate enough memory to hold all instance variables
- initialize the "isa" instance variable
- all other instances are set to 0
Consider that the "root" Cocoa object, NSObject, simply returns "self" in its init method.
But, if you want to be a good Obj-C citizen, you must use "init". It is part of the "contract" between you, the developer, and the environment.
You should always call one of the initializer methods especially when the class isn't your own. The pointer returned from init isn't necessarily the same as returned by alloc.
Read the documentation:
http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/doc/uid/20000050-init
Am I right in saying the equivalent of:
NSMutableArray *foo;
foo = [[NSMutableArray alloc] init];
[foo release];
Is C++:
NSMutableArray *foo = new NSMutableArray();
delete foo;
ie. The 2nd line of the Obj-C does the dynamic memory allocation, while first just makes a pointer? In this case, what is the function of [init] VS. [alloc]?
thanks guys - I'm almost finding a bit of C++ is almost a hindrance to learning Obj-C!
Internally C++ can be doing something very similar to alloc+init. In this case alloc does the actual memory allocation (the new), and init acts more or less as your constructor.
alloc is the equivalent of new() and init is the equivalent of a C++ object constructor.
I think the nearest C++ equivalent to Objective-C's two-stage alloc/init would be to call malloc to allocate a buffer, then use placement new to call the constructor for the previously-allocated memory block:
void *buffer = malloc(sizeof(NSMutableCPPArray));
NSMutableCPPArray *foo = new(buffer) NSMutableCPPArray();
In this example, the first line corresponds to alloc, dynamically allocating a new memory block for the object to use. The second line is similar to init, calling the constructor to initialize that memory block.
Of course, one key difference is that Objective-C's alloc/init pair is a fundamental and widely-used part of the standard Foundation library. Placement new, by contrast, is an odd and rarely-used corner of C++ that is loaded with caveats and warnings in the online C++ FAQ.
In addition to the basic semantic of the code you have showed, you have to consider the way memory is handled by the given programming languages. In Objective-C each object has a retain-count which is used when release is called (and an object needs a retain count of 0 before deletion). In C++ there is no such mechanism, and you have to handle memory all by your self when using new and delete (which can have memory leaks).
If you want memory management ala Objective-C you should check out the header of C++0x which includes the shared_ptr object (which behaves more alike Objective-C).
Note: I'm relatively new to Objective-C and am coming from Java and PHP.
Could someone explain to me why I always have to first allocate and then initialize an instance?
Couldn't this be done in the init methods like this:
+ (MyClass*)init {
MyClass *instance = [MyClass alloc];
[instance setFoo:#"bla"];
return instance;
}
+ (MyClass*)initWithString:(NSString*)text {
MyClass *instance = [MyClass init];
[instance setFoo:text];
return instance;
}
...
Is this just a relict from the old C days or is there something that I'm not seeing?
I know this isn't a problem as I could as well always call alloc and init, but since it's a bit tedious I'd like to at least know why I'm doing it.
I'm liking the expressiveness of the language so far, but this is something that I want to fully understand in order to think the Objective-C way.
Thank you!
+new ends up sending an +alloc message to the class and an -init message to whatever comes back from +alloc.
The reason that NeXT departed from Stepstone's convention of using the +new message (which was a Smalltalk idea) is that early on, they encountered situations where they wanted to be able to initialize the same object more than once.
Because creating an instance and initializing an instance are two separate jobs.
You send an alloc message to the class to get an uninitialized instance. You must then initialize the instance, and you often have several ways to do that. For example:
myStr = [[NSString alloc] init]; //Empty string
myStr = [[NSString alloc] initWithFormat:#"%#.%#", parentKeyPath, key];
myStr = [[NSString alloc] initWithData:utf16data encoding:NSUnicodeStringEncoding error:&error];
myStr = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error];
Each of these initializes the string in a completely different way. How you initialize the string depends on what you want to initialize it from.
Of course, nobody likes writing alloc and then init and then autorelease every time, so you usually have convenience methods (e.g., stringWithFormat:) that do all three steps for you.
Edit: For more on this topic, including essential insights from commenters, see my blog post “Reunification”.
See NSZone.
+alloc is a shortcut cut for +allocWithZone:, which is a mechanism Cocoa provides for optimizing memory allocation.
So you have the option to do something like this:
foo = [[NSString allocWithZone:MyZone] initWithString:#"Foo"];
foo2 = [foo copyWithZone:MyZone];
The idea behind memory zones is that if you have a large number of similar objects that are frequently allocated and deallocated it may more efficient to use a separate memory zone for those objects.
In order for zoning to be effective you'd want to have +allocWithZone: available to every NSObject subclass, hence you need to separate allocation and initialization. You can create and use all the shortcuts you want, like +new, but underneath it all you need an -init method that initializes an object that has already been allocated.
"Separating the allocation and initialization stages of instance creation provides many benefits. It’s possible to use any variation of the +alloc class method to allocate an instance and then use any available initializer with the new instance.This makes it possible to create your own initialization methods without needing to provide alternate implementations of all allocation methods.
New allocation methods are seldom created because the existing methods meet almost every need. However, one or more new initializers are created for almost every class. Due to the separation of allocation and initialization stages, initializer implementations only have to deal with the variables of new instances and can completely ignore the issues sur- rounding allocation.The separation simplifies the process of writing initializers. Furthermore, Cocoa standard initializers like -initWithCoder: work with instances regardless of the way memory for the instance was allocated.
One negative consequence of the separation of allocation and initialization is the need to be aware of conventions such as the designated initializer.You must know which methods are designated initializers and how to create and document new initializers in sub- classes. In the long run, using designated initializers simplifies software development, but there is an argument to be made that theTwo-Stage Creation pattern adds to the early learning curve for Cocoa developers."
(c) Cocoa Design Patterns by Erik M. Buck and Donald A. Yacktman
You don't have to. You can use [MyClass new]. This is similar to your hypothetical init method.
Basically, Objective-C, which didn't have garbage collection initially, separates the concept of memory allocation and class initialization. That's why there are two distinct methods. When you call alloc, you are explicitly allocating memory.
Most classes have what you are asking for. You have gotten answers before on why this is like it is and why you wouldn't always want to use this all the time but if you read the documentation to classes you will see many class methods that act this way and they are often used.
For NSString you have, for example:
+ (id)string // (Empty string)
+ (id)stringWithFormat:... // Formatted string (like you use)
+ (id)stringWithContentsOfURL:... // String populated with contents of URL
And so on. And you would then use this like: NSString *myString = [NSString stringWithFormat:#"Hello %#\n", userName];
Most other classes have this, like NSArray:
+ (id)array
+ (id)arrayWithContentsOfFile:...
+ (id)arrayWithContentsOfURL:...
+ (id)arrayWithObjects:...
You just need to read the documentation. :) And read the other replies on why you don't want to use this too much.
alloc : Memory is allocated/given to the object-reference. Now reference has the possession of the memory but has not done anything yet. This memory be empty(rarest case) or with some anonymous data.
alloc and init : Allocated memory is cleaned/emptied. Memory is initiated by zero bit.
alloc and initwithdata... : Allocated memory is initiated with desired data respected to properties of the class.
For example when you purchase a plot you get the possession. This plot is given to you as it is, ruined bricks or old house may be there. This is alloc.
When you clean your plot and remove all dirt and litter. This is alloc with init.
When you build that into some valuable house it becomes more meaningful to you. And it is alloc initwith...
Im getting fairly confused as the book im reading is delving into the NSNumber class and talks about all the different methods you can call on it. I have a couple questions:
1.) Do you not have to call a typical alloc or init on foundation classes?
2.)in what cases would you use, say, numberWithChar: as opposed to initWithChar (i think this is the part that is messing me up the most, not really sure im groking this concept on the level i need to be, if you folks could break it down for me I think it would really help me get over this humper-roo.
Thanks,
Nick
Class/Instance Analogies
Classes are like blueprints for a type house. Instances are like actual houses. So you can only have one blueprint for a single type of house, but you can have multiple actual houses of the same type. Also, you can have multiple blueprints, and each blueprint describes a different type of house.
Another analogy you can use is that classes are like cookie cutters, and instances are like cookies made from a cookie cutter.
How It Applies To Objective-C
There is one "class object" for every class in your code. To refer to the class object, you just use the class name. alloc is a class method that allocates a new instance like so:
MyWidget* w = [MyWidget alloc];
However, alloc doesn't initialize the class, so none of the member variables will be set up. init is an instance method that will initialize a newly allocated instance. So to allocate and initialize a new instance, you do this:
MyWidget* w = [[MyWidget alloc] init];
Which is equivalent to this:
MyWidget* w = [MyWidget alloc]; //alloc is being called on the class
w = [w init]; //init is being called on the instance
Another common type of class method is a factory method like numberWithChar:. This is basically what numberWithChar: does:
+(NSNumber*) numberWithChar:(char)c;
{
return [[[NSNumber alloc] initWithChar:c] autorelease];
}
The only real difference is that numberWithChar: returns an autoreleased object.
All objects must be allocated and initialized. That includes foundation classes.
1) alloc and init need to be called virtually always. numberWithChar is a convenience method, which means it calls alloc, init, and autorelease for you and returns the autoreleased instance.
2) Since numberWithChar returns an autoreleased object, that means unless you retain it (or pass it to something like an NSArray which will retain it), it'll be destroyed shortly. initWithChar returns a retain-ed object, which means you have to release it when you're done with it.
I found when I was starting out that it was helpful to use init-alloc as a rule, instead of the convenience methods, because it made me pay close attention to my memory management.
The difference between class and instance methods is addressed from a number of angles in the answers to this question What is the difference between class and instance methods?
EDIT:
To be honest, the analogy I use when I call a class method on, say NSString, is praying to the god of NSStrings to bestow upon me a magnificent new NSString. Notice that class methods are almost 100% used for creation. e.g. alloc is a class method, stringWithFormat is a class method, and so on.
Yes, it's ridiculous, I know.
Ok, first thing: In Objective-C, you don't call a method, you send a message to an object. The runtime looks up the methods and calls them.
It might help you to think of a class as a factory. In fact, years ago, we used to refer to class methods as factory methods.