初学iOS的童鞋都会见过这样一个格式:
- (id)init {
if (self = [super init]) { // equivalent to "self does not equal nil"
date = [[NSDate date] retain];
}
return self;
}
而为什么会这么“规定”,网上资料很多,都是说了面对象的继承性的安全问题
例如:http://blog.csdn.net/lamp_zy/article/details/8247563
http://www.zhihu.com/question/22295642
而在这里,我会从官方文档入手,先翻译官方文档的内容,再结合官方文档去解释init的深入理解的问题。
首先init方法:
- (instancetype)init;
是属于根类NSObject的一个方法,查看官方文档:Initialization
Initialization is the stage of object creation that makes a newly allocated object usable by setting its state to reasonable initial values. Initialization should always occur right after allocation. It is performed by an initializer method (or simply, an initializer), which you always invoke on a newly allocated object. Initializers can also perform other setup tasks that bring the object into a useful state, such as loading resources and allocating heap memory.
初始化是创建对象的一个阶段并且使得一个新分配的对象拥有一个理想的可用的初始化值。初始化总是需要在分配之后发生。它是用初始化方法来执行(或者简单的一个初始化值),你总是调用一个新分配的对象。初始化也可以在别的设置任务中被调用使得这个对象可用,例如分配资源和分配堆内存。
The Form of an Initializer Declaration
By convention, the name of an initializer always begins withinit. It returns a dynamically typed object (id) or, if initialization does not succeed,nil. An initializer can include one or more parameters that specify initial values.
Here is a sample declaration of an initializer from theNSString class:
<pre name="code" class="objc">- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
为了方便,初始化方法的开头总是init。这返回了一个动态的对象类型(id)或者,如果初始化不成功,返回nil值。一个初始化方法可以包括一个或多个参数来确定初始化值。
这里有NSString类的初始化声明的例子:
<span style="color:#339999;">- (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding</span>
Implementing an Initializer
A class generally implements an initializer for its objects, but is not required to. If a class does not implement an initializer, Cocoa calls the initializer of the nearest ancestor of the class. However, subclasses often define their own initializer or override an initializer of their superclass to add class-specific initializations. If a class does implement an initializer, it should invoke an initializer of its superclass as the first step. This requirement ensures a series of initializations for an object down the inheritance chain, starting with the root object. TheNSObject class declares theinit method as the default object initializer, so it is always invoked last but returns first.
一个类通常为一个对象实现了一个初始化方法,但并不是一定要这么做的。如果一个类并没有实现初始化方法,Cocoa框架会调用它的最近的类祖先的初始化方法。然而,子类经常定义它们的初始化方法或者重载它们的父类的初始化方法来添加类确定的初始化方法。如果一个类确实实现了一个初始化方法,它将会调用它的父类的初始化方法作为第一步。这个要求确保了在继承链上的一系列的对象初始化,从根对象开始。NSObject类声明了init方法作为默认的对象初始化方法, 所以它总是最后调用但是最早返回。
The basic steps for implementing an initializer method are the following:
- Invoke the superclass initializer and check the value it returns. (Use the reserved wordsuper to designate the superclass.) If the value is notnil, the superclass initializer has returned a valid object, so you may proceed with initialization.
- Assign values to the object’s instance variables. In memory-managed code, if those values are objects themselves, copy or retain them, as appropriate.
- Return the initialized object or, if initialization did not succeed, returnnil.
1.调用父类的初始化值并且检查它返回的值。(使用保留字super去指定父类)。如果返回的值不为空,超类初始化返回了一个有效的对象,所以你可以继续初始化过程。
2.分配值给对象的实例变量。在内存管理的代码中,如果这些值是对象的本身,适当地copy或者retain它们。 (就是init里面的retain或者copy操作嘛)
3.返回初始化对象,如果初始化失败的话,返回nil值。
Here is a simple initializer that follows these steps, initializing itsdate instance variable to the current date:
- (id)init {
if (self = [super init]) { // equivalent to "self does not equal nil"
date = [[NSDate date] retain];
}
return self;
}
In this code, if the superclass returns nil, the method skips initialization and returns that value to its caller.
A class may have multiple initializers. This occurs when the initialization data can take varied forms or where certain initializers, as a matter of convenience, supply default values. In this case, one of the initialization methods is called the designated initializer, which takes the full complement of initialization parameters.
下面是简单的初始化方法的步骤,将它的date实例变量初始化为当前的时间:
在这个代码块中,如果superclass返回空,这个方法将会跳过初始化过程,并且返回这个值给它的调用者。
一个类可能有多个初始化。当初始化数据时不同的形式这将会发生,为了方便起见,提供了一个缺省的值。在这种情况下,其中的一个初始化方法被指定成调用的初始化方法,它会满足整个初始化的参数配对。
Object creation
An object comes into runtime existence through a two-step process that allocates memory for the object and sets its state to reasonable initial values. To allocate an Objective-C object, send analloc or allocWithZone: message to the object’s class. The runtime allocates memory for the object and returns a “raw” (uninitialized) instance of the class. It also sets a pointer (known as theisa pointer) to the object’s class, zeros out all instance variables to appropriately typed values, and sets the object’s retain count to 1.
After you allocate an object, you must initialize it. Initialization sets the instance variables of an object to reasonable initial values. It can also allocate and prepare other global resources needed by the object. You initialize an object by invoking an init method or some other method whose name begins withinit. These initializer methods often have one or more parameters that enable you to specify beginning values of an object’s instance variables. If these methods succeed in initializing an object, they return it; otherwise, they returnnil. If an object’s class does not implement an initializer, the Objective-C runtime invokes the initializer of the nearest ancestor instead.
一个对象进入到runtime的存在周期经过两步:分配对象的内存和设置它为合理的初始化值。去分配一个Objective-C对象,发送alloc或者allocWithZone消息给对象的类。runtime分配对象的内存并且返回一个“raw” (在oracle的内存学习的时候见过, raw:原始,原材料) (uninitialized 未初始化的)类的实例。它同时也设置了指针(众所周知的事isa指针啦, 在调试的时候设置断点可以一层层看到,最底层的就是isa pointer)给对象的类,同时置空(zero out暂时这样翻译,以后有问题来修改)所有的实例变量成适当的类型值,同时将对象的retain count置为1。
在你allocate完一个对象后,你必须初始化它。初始化设置对象为一个合理的初始化值。它也能准备其他对象所需的全局资源。你初始化一个对象通过调用init方法或者其他以init开头的方法。这些初始化方法经常有着一个或者更多的参数来保证你的对象的实例化更明确。如果这些实例方法成功地初始化一个对象,它将返回它本身;否则,将返回nil。如果对象的类并没有实现初始化方法,Object-C的runtime调用它最近的祖先类的初始化方法来替代。
The Form of an Object-Creation Expression
A convention in Cocoa programming is to nest the allocation call inside the initialization call.
MyCustomClass *myObject = [[MyCustomClass alloc] init];
When you create an object using this form, you should verify that the returned value is notnil before proceeding. In memory-managed code, an object’s instance variables and other allocated memory should be deallocated before that object itself is released.
Object-Creation表达的形式:
Cocoa编程的一个约定俗成的就是嵌套allocation调用在 initialization调用中。
<span style="color:#339999;">MyCustomClass *myObject = [[MyCustomClass alloc] init];</span>
当你创建一个对象你使用这种形式,你应该验证它的返回值不为空才能继续以后的操作。在内存管理代码块中,一个对象的实例变量和其他分配内存应该被deallocated在这个对象它被release之前。
Memory-Management
In code that explicitly manages memory, the allocation and initialization procedure returns an object with a retain count of 1. This means that the client receiving the object now “owns” the object and is responsible for releasing it. You release it by sending it a release or autorelease message; the latter message causes a delayed release. If you do not release objects that you own, your program will leak memory.
内存管理
在代码中会明确地管理内存,allocation和initialzation过程返回对象的retain count为1.这意味着用户接收这个对象持有这个对象并且将负责它的释放。你释放它通过发送release或autorelease消息;后者会产生一个延迟释放。如果你没有释放应该释放的对象,你的程序将会内存泄漏。
Factory Methods
A factory method is a class method that, as a convenience to clients, creates an instance of a class. A factory method combines allocation and initialization in one step and returns an autoreleased instance of the class. Because the received object is autoreleased, the client must copy or retain the instance if it wants it to persist in memory. The names of factory methods have the following initial form:
+ (id)typeRemainderOfMethodName
where type is the class name minus the prefix and RemainderOfMethodName often begins withWith orFrom. For example,
+ (id)dataWithContentsOfURL:(NSURL *)url;
工厂方法
工厂方法是一种类方法,为了开发者的方便,创建类的实例对象,一个工厂方法把allocation和initialization合并在了一步同时返回了一个自动释放的实例对象。因为对象的接收者是自动释放的,开发者必须copy或者retain这个实例对象如果他们需要对象持久在内存中。工厂方法的名字有着这样的形式:
Multiple initializers
A class may define multiple initializer methods, either when it can take different forms of input or to provide default initialization values as a convenience to clients. If the class can take initialization data in different forms or from different sources, it can declare an initializer for each form or source. For example, theNSString class has initializers for obtaining string data as arrays of Unicode characters or from URL resources (among others).
Multiple initializers can also be a programming convenience. A class can have a series of initializers that, at one end, allow the client to specify all initial values and, at the other end, supply most or all of these values as defaults. Clients of the class may later be able to substitute new values for the default values through accessor methods or properties.
Framework classes sometimes have multiple factory methods as well as multiple initializers. They are similar in that they may be a convenience or take initialization data in different forms. However, they allocate the returned object as well as initialize it.
多重初始化:
一个类可能定义了多重初始化方法,或者当它输入不同形式的值或提供一个默认的初始化值作为客户端的便捷。如果这个类可以以不同的形式取初始化数据或者从不同的来源,它可以声明一种初始化方法对于不同的形式或者是数据源。例如,NSString为了获取string数据作为Unicode characters的数组或者是URL资源(等等)
多种初始化方法也是便于编程的。一个类可以有一系列初始化方法,在一端上,允许客户端确定所有的初始化值,在另一端,提供更多的或者所有的值作为默认值。类的对象可以稍后能够通过存取器或者属性来用新值替换默认值。
Framework类有时候拥有多工厂方法和多初始化方法。它们是相似于它们将会方便地或者以不同的方式获取初始化方法。然而,他们分配返回对象同时初始化它。
根据这个图很有意思, 硕哥也常用这种技巧,嵌套来获取初始化方法, 你可以这样定义动态方法,你可以这样定义类方法,注意到:Secondary initializer , 还有Designated initializer 指定的初始化 ,这里对Designated initializer了解就更加深入了, 因为在这个初始化方法里面是动用了copy 和 retain的哦,同时在上面的例子里面,在这个Designated initializer首次接触到了super , 就是对superclass的操作。
The Designated Initializer
The initializer of a class that takes the full complement of initialization parameters is usually the designated initializer. The designated initializer of a subclass must invoke the designated initializer of its superclass by sending a message to super. The convenience (or secondary) initializers—which can includeinit—do not callsuper. Instead they call (through a message toself) the initializer in the series with the next most parameters, supplying a default value for the parameter not passed into it. The final initializer in this series is the designated initializer.
指定的初始化器:
类的初始化采用了对初始化参数完整的补充通常就是designated initializer(网上别人译成:指定的初始化器)。子类的designated initializer必须通过发送super消息调用父类的designated initializer。便捷的(或二次)初始化-指的是包含init-而不调用super。作为替代性的它们调用(通过self的消息发送)初始化器在更多参数的一些系列,提供一个默认的参数值而不主动传递它。而这个初始化系列最后一个就是指定的初始化器。
注意哦,一个类可能多个designated initializer
可以参考:http://www.cocoachina.com/programmer/20140421/8204.html