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
Related
I recently learn objective-c from Programming Objective C, 4th edition.
I have question when reading to part:
myFraction = [Fraction alloc];
myFraction = [myFraction init];
When you send the alloc message to a class, you get back a new instance of that class. The alloc method is guaranteed to zero out all of an object’s instance variables. However, that doesn’t mean that the object has been properly initialized for use. You need to initialize an object after you allocate it.
Again, you are using a method here that you didn’t write yourself. The
init method initializes the instance of a class. Note that you are
sending the init message to myFraction. That is, you want to
initialize a specific Fraction object here, so you don’t send it to
the class—you send it to an instance of the class. Make sure you
understand this point before continuing.
So alloc and init is create each instance of class when I send message to class or instance of class?
I'm so confused about this. I searched on google but the result was found nothing. I need your help to make me clearly about it?
All of thing I know is alloc that allocate space in memory so it's actually not be created a new instance, just give me the address?
To begin with you just have some available memory with nothing in it.
When you call alloc, some of that free memory is reserved for your use for the instance that you are creating. Some basic setup work is done to configure the type of class that the instance is. Then you get a pointer back to the reserved memory location.
Technically, you could use this instance, but, it might not work properly in all cases as it hasn't been initialised. Some classes don't really need initialisation (like NSObject), some do. Generally you should never use the instance returned from alloc until you have called some init method.
After you call init, the instance is ready to use.
Sometimes the parameters that you pass to init mean that the initial instance that was reserved and created isn't the correct (class) type to use. In this case, it will be destroyed and a new one will be created for you. This is very common in class clusters where you create an NSArray instance, but then after calling init you might get back an NSCFArray. This is why you always need to use the instance returned from the init call, even though you already had the instance returned from alloc.
Usually you don't need to worry about this, but you do need to follow the rules.
So you always need to alloc and init an class.
Allocating means you give the class "Fraction" in this case a memory place. Afterwards you need to initialize the class "Fraction" so you can use it.
Fraction *class1 = [[Fraction alloc] init];
Fraction *class2 = [[Fraction alloc] init];
[class1 doSomethingWithClass1];
[class2 doSomethingWithClass2];
Later on you will learn about singletons. With that you can alloc/init a class one time, and always use that without alloc/init'ing it again.
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.
We know about the complete pattern of alloc/init that alloc and init must be combined.
NSObject *myObj = [[NSObject alloc] init];
1- init method receives the object from another source(not from a alloc,new,copy or alike or retained) so according to the fundamental memory management rule its not the owner and it must not release it. However, "Allocating and Initializing Objects / The Returned Object" article says that init could free the receiver.
How could this be possible when its against the fundamental rule?
2- Also, from the same article, init could return another object or nil. So, in this case, when we use the complete pattern of alloc/init, we could not release the object returned by alloc but we could only release the object returned from init and, init releases the object it received from alloc instead of us.
But init is not a alloc,new,copy or alike method so we must not release the object returned from it as it does not give us the ownership of object.
How could we release the object returned from init although this is against the fundamental rule?
3- Or, to adhere to the last paragraph of the same article, must we accept init method as a special case and use alloc/init pattern as an exception to the fundamental rule?
Memory Management Fundamental Rule:
You only release or autorelease objects you own.
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message.
You use release or autorelease to relinquish ownership of an object. autorelease just means “send a release message in the future” (to understand when this will be, see “Autorelease Pools”).
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
Allocating and Initializing Objects / The Returned Object:
However, in some cases, this responsibility can mean returning a different object than the receiver. For example, if a class keeps a list of named objects, it might provide an initWithName: method to initialize new instances. If there can be no more than one object per name, initWithName: might refuse to assign the same name to two objects. When asked to assign a new instance a name that’s already being used by another object, it might free the newly allocated instance and return the other object—thus ensuring the uniqueness of the name while at the same time providing what was asked for, an instance with the requested name.
In a few cases, it might be impossible for an init... method to do what it’s asked to do. For example, an initFromFile: method might get the data it needs from a file passed as an argument. If the file name it’s passed doesn’t correspond to an actual file, it won’t be able to complete the initialization. In such a case, the init... method could free the receiver and return nil, indicating that the requested object can’t be created.
Because an init... method might return an object other than the newly allocated receiver, or even return nil, it’s important that programs use the value returned by the initialization method, not just that returned by alloc or allocWithZone:. The following code is very dangerous, since it ignores the return of init.
id anObject = [SomeClass alloc];
[anObject init];
[anObject someOtherMessage];
Instead, to safely initialize an object, you should combine allocation and initialization messages in one line of code.
id anObject = [[SomeClass alloc] init];
[anObject someOtherMessage];
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html
The init method doesn't receive the object; the object receives the init message. The object does not possess itself; rather, it always knows about itself (through the implicit self argument in every message).
You're right that the object does not own itself, though. If alloc and init were fused in a single new method, that method would be its own (super) caller, so it would own the object (until it returns) and so be unquestionably right in releasing it. Since they are separate, and init is not the caller of alloc, you're right that it does not own the object, so you are right to question this practice.
This is one of the few cases where it's OK for one object to release an object (in this case, itself) on behalf of another. The alternative is not to release it, which, if you're going to either return nil or throw an exception, will be a leak.
In general, anytime you have an object retain or release itself, you should feel dirty. In this specific case, it's OK, because you are preventing a bug (a leak) rather than probably creating one.
2- Also, from the same article, init could return another object or nil. So, in this case, when we use the complete pattern of alloc/init, we could not release the object returned by alloc but we could only release the object returned from init and, init releases the object it received from alloc instead of us.
But init is not a alloc,new,copy or alike method so we must not release the object returned from it as it does not give us the ownership of object.
As init releases the old object on behalf of its caller, if it creates a new object, it does that on behalf of its caller. The caller does own the substitute object that init creates or retrieves for it.
As a corollary to this, if init retrieves a previously existing object, it must retain that, so that the caller will own it.
Again examining the hypothetical* new method, it would also need to both release the old object and create (owningly) or retain the substitute.
In all of these cases, it's init acting on behalf of its caller. It's normally dodgy for one method to do another's memory management, but for these cases, init doing it on behalf of its caller is necessary.
*The new method does exist, but simply sends alloc and init, so there's no need to implement it separately.
If initialization fails for some reason and must return null, then you must release the object in order to avoid leaking memory.
Similarly, init may decide to swap in a different object and return it - in that case you must also release the object in order to avoid leaking memory.
In both cases it's necessary because the original object isn't being returned by init, and will be orphaned after the method returns. Alloc has automatically retained the object, so if you don't release it its retain count will be stuck at 1 forever.
[Would another perspective help?]
The init method (and its siblings initWith... and similar) is a bit of an odd case but is not a special case of memory allocation rules. Init is odd because it has a name that sounds like it is going to change the internals of the instance but in fact it may do more than that (it may substitute some other object and initialize that object, for example). The tip-off is in the declaration of init:
- (id) init // the way it is
vs
- (void) init // in some other universe
The init method returns an object, so it might have been better named something like 'return an object that is (class-wise) an equivalent object and that has been initialized'. Most methods do not perform this kind of switcheroo, which makes init a bit different/odd.
There is nothing 'magic' about the alloc / init nesting -- it's just the simplest way to handle the fact that the object that you get back from alloc may not be the same object you get back from init. This works perfectly fine:
NSSomeClass* s = [NSSomeClass alloc];
s = [s init]; // that 's =' part is really important ;-)
and is exactly equivalent to the 'standard' idiom:
NSSomeClass* s = [[NSSomeClass alloc] init];
This is potentially problematic:
NSSomeClass* s = [NSSomeClass alloc]
[s init]; // bad! you ignored the result of init
The implementation of an init method must be done particularly carefully when the implementation returns a different object than the one it receives as the incoming 'self'. In such a case the init method takes on the responsibility of memory management of the 'self' object (because it's not going to return that object - so who else could be expected to do the management?)
It's possible to do some pretty ugly trickery, BTW. Don't try this at home!
// don't do this!
S* s = [S alloc]
[s retain]; // needs to survive 2 init's
S* ss = [s init......]; // s.retain goes 2-->1
S* sss = [s init.....]; // ... goes 1-->0;
Doing this is extremely poor practice because it depends on the init..... method always returning a new object (instead of the one it receives). That's an obviously bad assumption!
NOTE that by "a method receiving an object in 'self'" I mean that the method was invoked upon/by an object, and that object is made available by convention through the 'self' pointer.
The fundamental rule just doesn't apply in this special situation.
In fact, don't worry about it - unless you plan to do Posing, you won't need to write code that does this, and it will have no impact at all on the code you write.
You should continue to follow the fundamental rule in all your code.
And thirdly, the code is more what you'd call "guidelines" than actual rules.
(Captain Barbosa)
alloc/init is a bit of a special case. You have to do the retain/release stuff inside init in such a way that whatever object the caller gets back is owned by the caller and there are no leaks.
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.