摘自:http://www.apple.com.cn/developer/mac/library/documentation/Cocoa/Conceptual/CocoaFundamentals/Introduction/chapter_1_section_1.html
Cocoa对象的创建总是分成两个阶段:对象分配和初始化。
Cocoa会从应用程序的虚存区中为对象分配足够的内存。在计算需要分配多少内存时,Cocoa会考虑对象的实例变量,包括它们的类型和顺序,这些信息由对象的类来定义。为了进行对象分配,您需要向对象的类发送alloc或allocWithZone:消息。在消息的返回值中可以得到一个“生的”(未初始化的)类实例。alloc方法使用应用程序缺省的虚存区。区是一个按页对齐的内存区域,用于存放应用程序分配的对象和数据。
除了分配内存之外,Cocoa的分配(allocation)消息还进行其它一些重要的工作:
§ 将对象的保持数设置为1。
§ 使初始化对象的isa
实例变量指向对象的类。对象类是一个根据类定义编译得到的运行时对象。
§ 将其它所有的实例变量初始化为0(或者与0等价的类型,比如nil
、NULL
、和0.0
)。
对象的isa实例变量是从NSObject继承下来的,因此所有的Cocoa对象都有。在将isa指针指向对象类之后,对象就被集成到继承层次的运行时视图和构成程序的对象(类和实例)网络中了。其结果是对象可以找到它所需要的所有运行时信息,比如其它对象在继承层次上的位置,它们遵循的协议,以及在响应消息时可以执行的方法实现的位置。
初始化过程将对象的实例变量设置为合理而有用的初始值,还可以分配和准备对象需要的其它全局资源,并在必要时装载诸如文件这样的资源。声明实例变量的所有对象都应该实现一个初始化方法-除非将所有变量都置为0的缺省初始化已经足够。如果一个对象没有实现自己的初始化方法,Cocoa就会调用其最近的祖先对象的方法。
NSObject声明了init方法作为初始化方法的原型,它是一个实例方法,返回一个类型为id的对象。对于不需要初始化其它数据的子类,重载init方法就可以了,但是常见的情况是初始化阶段需要根据外部的数据来设置对象的初始状态。唯一的要求是初始化方法必须以“init”字母开头(有时用格式规则描述init...来表示初始化方法)。从初始化方法返回nil表示不能创建被请求的对象。在创建对象时,通常应该在处理之前检查返回值是否为nil。一旦对象被初始化了,就不应该再进行初始化。如果您试图进行重复初始化,实例化对象的框架类通常会产生一个例外。
实现一个init... 方法,使之作为类的唯一初始化方法或者具有多个初始化方法的类的指定初始化方法时(参见"多个初始化方法和指定初始化方法"部分的描述),有如下几个关键步骤:
§ 总是首先调用超类(super
)的初始化方法。
§ 检查超类返回的对象。如果是nil
,则初始化不能进行,需要向接收者对象返回nil
。
§ 在初始化实例变量时,如果它们是其它对象的引用,则在必要时进行保留和拷贝。
§ 将实例变量设置为正当的初始值之后,就返回self
,除了下列的情况:
§ 需要返回一个代替对象,在这种情况下,首先释放新分配的对象。
§ 某些问题导致不能成功初始化,这时需要返回nil
。
在很多方面,一个类的dealloc方法都是和init... 方法(特别是指定初始化方法)相呼应的。初始化方法在对象分配之后马上被调用,而dealloc在对象的销毁之前被调用;初始化方法确保对象的实例变量被正确初始化,而dealloc方法确保该对象的实例变量被释放,以及确保动态分配的内存被释放。
两者的最后一点相似之处在于必须调用各自的超类实现。在初始化方法中,首先调用超类的指定初始化方法;在dealloc方法中,则在最后一步调用超类的dealloc实现。这样做的原因是与初始化方法相反,子类应该在祖先类的实例变量被释放之前释放自己拥有的实例变量。
类工厂方法的实现是为了向客户提供方便,它们将分配和初始化合在一个步骤中,返回被创建的对象,并进行自动释放处理。这些方法的形式是+ (type)className...(其中className不包括任何前缀)。