为什么我不应该将 alloc 和 init 分开?

Why should I not separate alloc and init?

在Objective-C中初始化和分配的正常方法是

NSObject *someObject = [[NSObject alloc] init];

为什么下面的不练?

NSObject *someObject = [NSObject alloc];
[someObject init];

因为它不那么简单而且更容易出错。

分配但未初始化的对象是无用的,因此将分配和初始化放在一行中是有意义的。如果将它们分开,则如果这两行不是紧接在一起(可能在重构之后),则更容易出现错误和错误,这可能会导致在尝试使用未初始化的对象时出错。

allocinit 分行并没有一个很好的理由,反对它的理由有很多。

主要问题是您最终可能会使用错误的对象。

init 在许多 classes 中是特殊的,因为它可能只是释放接收器,而是创建一个驻留在不同地址的新对象。所以你的 someObject 然后指向错误的(未初始化的)实例。

有很多框架 classes 使用 init 方法的参数来决定最好使用哪种专门的 subclass。这种情况经常发生在 class 集群中,如 NSStringNSArray,但它确实可能发生在每种对象上。

您可以看到初始化程序的这种特殊行为的一个地方是 ARC:It explicitly declares that the init family of methods eats up the receiver and returns a +1 retained object。如果初始化程序总是 return 接收者,则没有必要这样做。

当然你可以通过做另一个作业来修复你的代码:

NSObject *someObject = [NSObject alloc];
someObject = [someObject init];

这将解决问题。但是这样做也没有意义。

来自对象初始化官方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

同一文档的另一个原因是:

Once an object is initialized, you should not initialize it again

给出这个例子:

NSString *aStr = [[NSString alloc] initWithString:@"Foo"];
aStr = [aStr initWithString:@"Bar"];

其中:

the second initialization in this example would result in NSInvalidArgumentException being raised.

根据我的理解,分配的对象在没有被初始化的情况下是没有意义的,

如果您先 alloc 一个对象然后计划对其进行初始化,则可能会出现忘记初始化对象并直接调用其任何实例方法的情况,这将导致运行 时间错误。

示例:

    NSString *str = [NSString alloc];
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
NSLog(@"%ld",str.length);

当我运行上面的代码时,我在我的控制台中得到了这个

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]!'

如果我做下面的事情,我仍然会得到异常,因为 str 没有被初始化,因为正在初始化的任何东西都没有被 str

消耗或指向
[str init];

因此,如果您想分两行进行,应该像这样

NSObject *someObject = [NSObject alloc];
someObject = [someObject init];

但让它们嵌套总是更好

NSObject *someObject = [[NSObject alloc]init];

如果您打算在单行上执行此操作,请使用 new 关键字,该关键字可在单行上实现分配和初始化的目的。

示例: YourClass *object_ofClass = [YourClass new];