Using the new
factory method might seem appealing: you no longer have to type [[MyClass alloc] init]
, you no longer need to write custom factory methods to your class, in short less code. And this is not a bad thing, less code to write means less code to maintenance, test, etc.
new
unfortunately has a big flaw, mainly caused by the fact that new
translates to alloc
+init
. This makes it easy to mistakenly use init
where you should not be allowed to. One situation that falls into this category is when init
is declared with the NS_UNAVAILABLE attribute, which causes compile errors when used directly.
Let’s consider a short example:
@interface MyPerson: NSObject
@property (nonatomic, readonly, strong, nonnull) NSString *name;
- (nonnull instancetype)init NS_UNAVAILABLE;
- (nonnull instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER;
@end
Code language: Objective-C (objectivec)
We try to be very clear and specific regarding the class: it should have a non-nil name, and you should be able to instantiate it only via the initWithName:
intializer. The basic init
would not make sense here, since we’d end up with an invalid instance (name
would be nil), so we mark it as unavailable.
Trying to write [[MyPerson alloc] init]
results in a clear compile error: 'init' is unavailable
. On the other hand [MyPerson new]
successfully compiles and silently fails at runtime as we end up with an invalid instance. This can result in some bugs hard to find, especially if new
is used only in some places of the application.
And even if new makes sense at the time the class is written – i.e. init
gives a valid instance, things can change in the future if other developer (or even yourself) change the class initializers and make init
unavailable, at which point things might start to go wild if some of the new
calls are missed and not replaced by the new ones. On the other hand alloc init
doesn’t suffer from this problem, as you’ll instantly get compile errors all over the place where the construct is used.
Swift handles this a little bit better by crashing the app if new
is used on a class that has init
exported as unavailable – for example if you add a required parametrized initializer to the class. The code still compiles, but you no longer get a silent failure, and the app simply crashes. This helps as it gives you the exact root cause of the problem, but, depending on the application, might not be a preferable solution.
alloc init
gives you bug free code courtesy of the compiler. new
leads to error prone and less forward compatible code. Let’s stop using it.
Recent Comments