OC为何很少new一个对象?
前言
对于OC,我们最常用的生成一个对象的方式是下面这样的
NSObject *obj = [[NSObject alloc] init];
当然也会有下面这种方式
NSObject *obj = [NSObject new];
但是这种方式是很少用的。对于大部分人的理解,其实new的效果和结果是和alloc组合init是一样的,那么既然如此,为何大家均选择了调用两个方法的稍微复杂点的方式,而并没选择调用一个方法new的简单方式呢?
OC为何很少new一个对象?
苹果官方解释
下面是苹果官方文档
Type Method
# new
Allocates a new instance of the receiving class, sends it an [init]
message, and returns the initialized object.
Framework
* Objective-C Runtime
## Declaration
+ (instancetype)new;
## Return Value
A new instance of the receiver.
## Discussion
This method is a combination of [alloc] and [init]. Like [alloc], it
initializes the `isa` instance variable of the new object so it points to
the class data structure. It then invokes the [init] method to complete
the initialization process.
关键则是后面的两句
Allocates a new instance of the receiving class, sends it an [init]
message, and returns the initialized object.
//生成一个新的实例对象,并发送一个[init]方法,然后返回初始化过的对象
This method is a combination of [alloc] and [init]. Like [alloc], it
initializes the `isa` instance variable of the new object so it points to
the class data structure. It then invokes the [init] method to complete
the initialization process.
//[new]方法是后面两个方法的结合,也就是:[alloc]和[init]. [alloc]:
初始化一个新对象的isa实例变量,并且指向其对应的类数据结构。然后调用[init]方法去完成初始化过程
从解释可以看出,[new]方法是后面两个方法的结合,也就是:[alloc]和[init]。并且作用也是和这两个方法是一样的。从权威的官方文档解释,我们仍然看不出两者之间的区别。
GNUstep解释
偶然间,我在另一个权威的代码文档中发现了他们之间的不同点,那就是GNUstep。GNUstep是GNU对OC的开源,可以说是除苹果外,对于OC最权威以及正确的一份代码资料了。下面则是GNUstep对于new的解释
/**
* This method is a short-hand for alloc followed by init, that is,
* NSObject *object = [NSObject new];
* is exactly the same as
* NSObject *object = [[NSObject alloc] init];
* This is a general convention: all <code>new...</code>
* methods are supposed to return a newly allocated and
* initialized instance, as would be generated by an
* <code>alloc</code> method followed by a corresponding
* <code>init...</code> method. Please note that if you are
* not using a garbage collector, this means that instances
* generated by the <code>new...</code> methods are not
* autoreleased, that is, you are responsible for releasing
* (autoreleasing) the instances yourself. So when you use
* <code>new</code> you typically do something like:
* NSMutableArray *array = AUTORELEASE ([NSMutableArray new]);
* You do not normally need to override <code>new</code> in
* subclasses, because if you override <code>init</code> (and
* optionally <code>allocWithZone:</code> if you really
* need), <code>new</code> will automatically use your
* subclass methods.
* You might need instead to define new <code>new...</code>
* methods specific to your subclass to match any
* <code>init...</code> specific to your subclass. For
* example, if your subclass defines an instance method
* initWithName:
* it might be handy for you to have a class method
* newWithName:
* which combines <code>alloc</code> and
* <code>initWithName:</code>. You would implement it as follows:
* + (id) newWithName: (NSString *)aName
* {
* return [[self alloc] initWithName: aName];
* }
*/
+ (id) new
{
return [[self alloc] init];
}
我给大家找出了关键点,如下
* Please note that if you are
* not using a garbage collector, this means that instances
* generated by the <code>new...</code> methods are not
* autoreleased, that is, you are responsible for releasing
* (autoreleasing) the instances yourself. So when you use
* <code>new</code> you typically do something like:
* NSMutableArray *array = AUTORELEASE ([NSMutableArray new]);
这句话的意思很明显了,就是说,如果你没使用垃圾回收(这里的意思是指,ARC,因为OC一直是一门具有垃圾回收机制的一门语言)的话,也就是在MRC下,使用new生成的实例对象,将不会自动释放,将由你手动管理对象的release。
其实我理解这句话的意思就是,如果在MRC下,使用new的时候,写代码的话,主要就得写成下面这样:
NSMutableArray *array = AUTORELEASE ([NSMutableArray new]);
这样的写法也是和普通的写法有很大不同的,之后现在在来看看这个AUTORELEASE
image.png
从图中可以看到:AUTORELEASE函数的这种隐式声明早已经在c99就不合法了。
最终解释
OC是一门上世纪八十年代就诞生的一门语言,但是ARC则是Xcode4开始才支持的,而Xcode4则是在2011年才发布的。也就是说,在长达接近三十年的时间里,OC都是在MRC下编写代码的,从上面GNU文档里的解释可以看出:
1、在MRC下,new的对象release方式的不同点,因此大家就选择了相对复杂的[alloc]和[init]的组合方式,并在长达三十年的代码风格中形成了风俗和习惯,并衍生至今。
2、当然,如果用new生成一个对象的话,那么初始化方法就只能调用到init,而不能调用到自定义的initWith等方法,然而我们实际开发中,却常自定义init方法,因此new就在此种情况下不太合适
从上面文档解释也能知道的一点是:在如今的ARC下,其实[new]和[[alloc] init]是没什么区别的,从官方文档的解释和GNU源码也能看得出来,他两是一样的。