The normal way to initialise and allocate in Objective-C is
NSObject *someObject = [[NSObject alloc] init];
Why is the following not practised
As per my understanding an allocated object makes no sense without it being initialized,
if you alloc
an object first and then later plan to initialize it, there might be a case that you may forget to initialize the object and give a direct call to any of its instance method which would result in run time error.
Example:
NSString *str = [NSString alloc];
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
NSLog(@"%ld",str.length);
When i run the above code i get this in my console
Did you forget to nest alloc and init?
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -length only defined for abstract class. Define -[NSPlaceholderString length]!'
if i would do the below I would still get the exception as str is not being initialized because whatever is being initialized is not being consumed or pointed by str
[str init];
Hence if you want to do it in two lines it should be like this
NSObject *someObject = [NSObject alloc];
someObject = [someObject init];
But it's always better to keep them nested
NSObject *someObject = [[NSObject alloc]init];
If you plan on doing it on single line then use the new
keyword which servers the purpose of allocation and initialization on a single line.
Example: YourClass *object_ofClass = [YourClass new];
From the Object Initialization official documentation:
Because an init... method might return nil or an object other than the one explicitly allocated, it is dangerous to use the instance returned by alloc or allocWithZone: instead of the one returned by the initializer
Another reason from the same document is that:
Once an object is initialized, you should not initialize it again
given this example:
NSString *aStr = [[NSString alloc] initWithString:@"Foo"];
aStr = [aStr initWithString:@"Bar"];
where:
the second initialization in this example would result in NSInvalidArgumentException being raised.
Because it is less simple and more error-prone.
An allocated but not initialised object is useless, so it make sense to put allocation and initialisation in one line. If they are separated, there is more possibility for errors and bugs if the two lines are not directly after each other (perhaps after refactoring), which may lead to errors while trying to use an uninitialised object.
There simply isn't a single good reason to alloc
and init
in separate lines, and many reasons against it.
The main problem is that you might end up using the wrong object.
init
is special in many classes as it might just release the receiver and instead create a new object that resides at a different address. So your someObject
then points to the wrong (uninitialized) instance.
There are a lot of framework classes that use the arguments of the init
method to decide which kind of specialized subclass is best to use. This frequently happens with class clusters like NSString
or NSArray
but it can really happen with each kind of object.
One place where you can see this special behavior of initializers is ARC: It explicitly declares that the init family of methods eats up the receiver and returns a +1 retained object. This would not be necessary if initializers would just always return the receiver.
Of course you could fix your code by just doing another assignment:
NSObject *someObject = [NSObject alloc];
someObject = [someObject init];
This would fix the problem. But there's also no sense in doing it.