Object Initialization(对象初始化)

Initialization sets the instance variables of an object to reasonable and useful initial values. It can also allocate and prepare other global resources needed by the object, loading them if necessary from an external source such as a file. Every object that declares instance variables should implement an initializing method—unless the default set-everything-to-zero initialization is sufficient. If an object does not implement an initializer, Cocoa invokes the initializer of the nearest ancestor instead.

初始化方法赋予对象的实例变量一个合理有用的初始值。它也为对象所需的全局资源分配和准备空间,在需要的时候从外部资源进行加载。每一个声明了实例变量的对象都应该实现相应的初始化方法,除非默认的将所有的实例初始化为零的初始化就已经满足要求。如果一个对象没有实现初始化方法,Cocoa将调用继承链中最近的祖先的初始化方法。

The Form of Initializers(初始化方法)

NSObject declares the init  prototype for initializers; it is an instance method typed to return an object of type  id . Overriding  init  is fine for subclasses that require no additional data to initialize their objects. But often initialization depends on external data to set an object to a reasonable initial state. For example, say you have an  Account  class; to initialize an  Account  object appropriately requires a unique account number, and this must be supplied to the initializer. Thus initializers can take one or more parameters; the only requirement is that the initializing method begins with the letters “init”. (The stylistic convention  init...  is sometimes used to refer to initializers.)

NSObject类为初始化声明了init原型;它是一个返回id类型的实例方法。对初始化时不需要外部数据的对象来说,重写init方法是不错的选择。但是通常情况下,初始化过程都依赖于外部数据。举个例子,假如你有一个名为Account的类;初始化一个合适的Account对象需要一个唯一的account number,并且这个account number必须传入初始化方法。好在初始化方法可以接收多个参数;唯一的要求是初始化方法使用“init”字符开头(格式上的约定init……用来标注初始化器)

Note: Instead of implementing an initializer with parameters, a subclass can implement only a simple init method and then use “set” accessor methods immediately after initialization to set the object to a useful initial state. (Accessor methods enforce encapsulation of object data by setting and getting the values of instance variables.) Or, if the subclass uses properties and the related access syntax, it may assign values to the properties immediately after initialization.

注意:除了实现一个带有参数的初始化方法,子类也可以通过实现一个简单的init方法,然后紧跟初始化方法使用“set”方法来使对象达到想要的初始化状态。(存取器方法可以设置和获取实例变量的值,从而实现数据的封装)。或者子类使用了属性和相应的access语法,则可以设置属性的值紧跟初始化方法之后。

Cocoa has plenty of examples of initializers with parameters. Here are a few (with the defining class in parentheses):

    Cocoa有很多带有参数的初始化方法。下面举一些例子(括号里面是所定义的类)

    • - (id)initWithArray:(NSArray *)array; (from NSSet)

    • - (id)initWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)anotherDate; (from NSDate)

    • - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag; (from NSWindow)

    • - (id)initWithFrame:(NSRect)frameRect; (from NSControl and NSView)

    These initializers are instance methods that begin with “init” and return an object of the dynamic type id. Other than that, they follow the Cocoa conventions for multiparameter methods, often using WithType: or FromSource: before the first and most important parameter.
    这些初始化方法都是以“init”开头的实例方法且返回动态id类型。除此之外,他们遵循Cocoa的多参数方法惯例,使用“WithType:”或者“FromSource:”在第一个和和最主要的参数之前。

    Issues with Initializers

    Although init... methods are required by their method signature to return an object, that object is not necessarily the one that was most recently allocated—the receiver of the init... message. In other words, the object you get back from an initializer might not be the one you thought was being initialized.

    尽管init……方法被他们的方法签名要求返回一个对象,该对象并不是必须是init……方法的接收者。换句话说,从初始化方法中返回的对象或许不是如你所想的进行初始化

    Two conditions prompt the return of something other than the just-allocated object. The first involves two related situations: when there must be a singleton instance or when the defining attribute of an object must be unique. Some Cocoa classes—NSWorkspace, for instance—allow only one instance in a program; a class in such a case must ensure (in an initializer or, more likely, in a class factory method) that only one instance is created, returning this instance if there is any further request for a new one. 

    两种情况迅速的返回something而不是进行分配内存后的对象。第一种包括两种情形:单例和被定义的对象属性是唯一的。例如NSWorkspace,一个程序中只允许一个实例;在这种情况下类必须保证(在一个初始化方法,或者类方法)只有一个实例被创建,当接受到请求新的实例的时候返回同一个实例。

    A similar situation arises when an object is required to have an attribute that makes it unique. Recall the hypothetical Account class mentioned earlier. An account of any sort must have a unique identifier. If the initializer for this class—say, initWithAccountID:—is passed an identifier that has already been associated with an object, it must do two things:

    类似的情况,当一个对象要求其某一个属性是唯一的。回想之前假设的Account类。Account类的实例必须有一个唯一的id。假如Account类有这样一个初始化方法

    initWithAccountID:并且接收了一个已经使用过的id,它必须做下面两件事:
    • Release the newly allocated object (in memory-managed code) 释放新分配的对象内存

    • Return the Account object previously initialized with this unique identifier 返回之前使用该唯一id创建的对象

    By doing this, the initializer ensures the uniqueness of the identifier while providing what was asked for: an Account instance with the requested identifier.

    这样,这个初始化过程就为Account对象保证了唯一的id

    Sometimes an  init...  method cannot perform the  initialization requested. For example, an  initFromFile:  method expects to initialize an object from the contents of a file, the path to which is passed as a parameter. But if no file exists at that location, the object cannot be initialized. A similar problem happens if an  initWithArray:  initializer is passed an NSDictionary  object instead of an NSArray  object. When an  init...  method cannot initialize an object, it should:

    有时,init……方法不能按初始化方法所要求的执行。举个例子,initFromFile:方法希望使用一个文件的内容来初始化对象。文件的路径作为参数传入方法,但是如果文件不存在于指定的路径,那么对象就不能初始化。类似的问题,将NSDictionary对象代替NSArray对象传入initWithArray方法。当init……方法不能初始化一个对象,它应当:
    • Release the newly allocated object (in memory-managed code) 释放为新对象分配的内存

    • Return nil 返回nil

    Returning  nil  from an initializer indicates that the requested object cannot be created. When you create an object, you should generally check whether the returned value is  nil  before proceeding:

    初始化返回nil表明期望的对象不能被创建。当你使用初始化方法创建一个对象时,你应当总是检查返回的值是否是nil。

    id anObject = [[MyClass alloc] init];
    if (anObject) {
    [anObject doSomething];
    // more messages...
    } else {
    // handle error
    }

    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. Consider the following code
    由于init……方法或许会返回nil,或者是一个你不期望的对象,直接使用alloc或者allocWithZone:生成的实例是很危险的,如下情形:

    id myObject = [MyClass alloc];
    [myObject init];
    [myObject doSomething];

    The  init  method in this example could have returned  nil  or could have substituted a different object. Because you can send a message to  nil  without raising an exception, nothing would happen in the former case except (perhaps) a debugging headache. But you should always rely on the initialized instance instead of the “raw” just-allocated one. Therefore, you should nest the allocation message inside the initialization message and test the object returned from the initializer before proceeding.

    上例中,init方法或许会返回nil或者一个不是你所期待的对象。向nil发送消息并不会引发错误,所以调试起来很头疼。你应当嵌套初始化消息在初始化方法的内部,并且检测方法的返回对象。

    id myObject = [[MyClass alloc] init];
    if ( myObject ) {
    [myObject doSomething];
    } else {
    // error recovery...
    }

    Once an object is initialized, you should not initialize it again. If you attempt a reinitialization, the framework class of the instantiated object often raises an exception. For example, the second initialization in this example would result in NSInvalidArgumentException being raised.
    对象初始化完成后,你不能再次进行初始化。如果你尝试重新初始化,实例化的framework class将报错。如下例,第二次初始化时将导致NSInvalidArgumentException错误

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

    Implementing an Initializer

    There are several critical rules to follow when implementing an  init...  method that serves as a class’s sole initializer or, if there are multiple initializers, its  designated initializer  (described in  Multiple Initializers and Designated Initializer ):
    在实现类的初始化方法时,有几种公认的规则需要遵守,如基础的初始化方法, Multiple Initializers,指定初始化方法。
    • Always invoke the superclass (super) initializer first.

    • Check the object returned by the superclass. If it is nil, then initialization cannot proceed; return nil to the receiver. 

    • When initializing instance variables that are references to objects, retain or copy the object as necessary (in memory-managed code).初始化对象的实例变量,在需要的时候调用retain和release

    • After setting instance variables to valid initial values, return self unless: 在为实例变量设置好有效的值后,返回self除非:

      • It was necessary to return a substituted object, in which case release the freshly allocated object first (in memory-managed code).要求返回一个替代的对象,这种情况下要先释放新分配的对象

      • A problem prevented initialization from succeeding, in which case return nil.在初始化的过程中发生了问题导致不能继续,返回nil

    - (id)initWithAccountID:(NSString *)identifier {
    if ( self = [super init] ) {
        Account *ac = [accountDictionary objectForKey:identifier];
            if (ac) { // object with that ID already exists
              [self release];
              return [ac retain];
            }
            if (identifier) {
              accountID = [identifier copy]; // accountID is instance variable
              [accountDictionary setObject:self forKey:identifier];
              return self;
             } else {
              [self release];
              return nil;
            }
      } else
     return nil;
    }
    Note:  Although, for the sake of simplicity, this example returns  nil  if the parameter is  nil , the better Cocoa practice is to raise an exception.
    注意:尽管上例中,参数为nil的时候返回nil,更好的Cocoa体验是在此时产生一个警告

    It isn’t necessary to initialize all instance variables of an object explicitly, just those that are necessary to make the object functional. The default set-to-zero initialization performed on an instance variable during allocation is often sufficient. Make sure that you retain or copy instance variables, as required for memory management.
    清晰的初始化对象的实例变量是没有必要的,只需要注意那些对对象功能有影响的实例变量。默认的在allocation阶段进行的set-to-zero初始化方法已经满足。确保对实例变量进行了适当的retain和copy操作

    The requirement to invoke the superclass’s initializer as the first action is important. Recall that an object encapsulates not only the instance variables defined by its class but the instance variables defined by all of its ancestor classes. By invoking the initializer of super first, you help to ensure that the instance variables defined by classes up the inheritance chain are initialized first. The immediate superclass, in its initializer, invokes the initializer of its superclass, which invokes the main init... method of its superclass, and so on (see Figure 6-1). The proper order of initialization is critical because the later initializations of subclasses may depend on superclass-defined instance variables being initialized to reasonable values.
    Inherited initializers are a concern when you create a subclass. Sometimes a superclass init... method sufficiently initializes instances of your class. But because it is more likely it won’t, you should override the superclass’s initializer. If you don’t, the superclass’s implementation is invoked, and because the superclass knows nothing about your class, your instances may not be correctly initialized.
    • 1
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    第0章 导读(译者的话) 第1章 关于对象Object Lessons) 加上封装后的布局成本(Layout Costs for Adding Encapsulation) 1.1 C++模式模式(The C++ Object Model) 简单对象模型(A Simple Object Model) 表格驱动对象模型(A Table-driven Object Model) C++对象模型(Th e C++ Object Model) 对象模型如何影响程序(How the Object Model Effects Programs) 1.2 关键词所带来的差异(A Keyword Distinction) 关键词的困扰 策略性正确的struct(The Politically Correct Struct) 1.3 对象的差异(An Object Distinction) 指针的类型(The Type of a Pointer) 加上多态之后(Adding Polymorphism) 第2章 构造函数语意学(The Semantics of constructors) 2.1 Default Constructor的建构操作 “带有Default Constructor”的Member Class Object “带有Default Constructor”的Base Class “带有一个Virual Function”的Class “带有一个virual Base class”的Class 总结 2.2 Copy Constructor的建构操作 Default Memberwise Initialization Bitwise Copy Semantics(位逐次拷贝) 不要Bitwise Copy Semantics! 重新设定的指针Virtual Table 处理Virtual Base Class Subobject 2.3 程序转换语意学(Program Transformation Semantics) 明确的初始化操作(Explicit Initialization) 参数的初始化(Argument Initialization) 返回值的初始化(Return Value Initialization) 在使用者层面做优化(Optimization at the user Level) 在编译器层面做优化(Optimization at the Compiler Level) Copy Constructor:要还是不要? 摘要 2.4 成员们的初始化队伍(Member Initialization List) 第3章 Data语意学(The Semantics of Data) 3.1 Data Member的绑定(The Binding of a Data Member) 3.2 Data Member的布局(Data Member Layout) 3.3 Data Member的存取 Static Data Members Nonstatic Data Member 3.4 “继承”与Data Member 只要继承不要多态(Inheritance without Polymorphism) 加上多态(Adding Polymorphism) 多重继承(Multiple Inheritance) 虚拟继承(Virtual Inheritance) 3.5 对象成员的效率(Object Member Efficiency) 3.6 指向Data Members的指针(Pointer to Data Members) “指向Members的指针”的效率问题 第4章 Function语意学(The Semantics of Function) 4.1 Member的各种调用方式 Nonstatic Member Functions(非静态成员函数) Virtual Member Functions(虚拟成员函数) Static Member Functions(静态成员函数) 4.2 Virtual Member Functions(虚拟成员函数) 多重继承下的Virtual Functions 虚拟继承下的Virtual Functions 4.3 函数的效能 4.4 指向Member Functions的指针(Pointer-to-Member Functions) 支持“指向Virtual Member Functions”之指针 在多重继承之下,指向Member Functions的指针 “指向Member Functions之指针”的效率 4.5 Inline Functions 形式对数(Formal Arguments) 局部变量(Local Variables) 第5章 构造、解构、拷贝 语意学(Semantics of Construction,Destruction,and Copy) 纯虚拟函数的存在(Presence of a Pure Virtual Function) 虚拟规格的存在(Presence of a Virtual Specification) 虚拟规格中const的存在 重新考虑class的声明 5.1 无继承情况下的对象构造 抽象数据类型(Abstract Data Type) 为继承做准备 5.2 继承体系下的对象构造 虚拟继承(Virtual Inheritance) 初始化语意学(The Semantics of the vptr Initialization) 5.3 对象复制语意学(Object Copy Semantics) 5.4 对象的功能(Object Efficiency) 5.5 解构语意学(Semantics of Destruction) 第6章 执行期语意学(Runting Semantics) 6.1 对象的构造和解构(Object Construction and Destruction) 全局对象(Global Objects) 局部静态对象(Local Static Objects) 对象数组(Array of Objects) Default Constructors和数组 6.2 new和delete运算符 针对数组的new语意 Placement Operator new的语意 6.3 临时性对象(Temporary Objects) 临时性对象的迷思(神话、传说) 第7章 站在对象模型的类端(On the Cusp of the Object Model) 7.1 Template Template的“具现”行为(Template Instantiation) Template的错误报告(Error Reporting within a Template) Template中的名称决议方式(Name Resolution within a Template) Member Function的具现行为(Member Function Instantiation) 7.2 异常处理(Exception Handling) Exception Handling快速检阅 对Exception Handling的支持 7.3 执行期类型识别(Runtime Type Identification,RTTI) Type-Safe Downcast(保证安全的向下转型操作) Type-Safe Dynamic Cast(保证安全的动态转型) References并不是Pointers Typeid运算符 7.4 效率有了,弹性呢? 动态共享函数库(Dynamic Shared Libraries) 共享内存(Shared Memory)

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值