【翻译】(objc-2)对象,类和消息

Objective-C编程语言自译 专栏收录该内容
2 篇文章 0 订阅

【翻译】(objc-2)对象,类和消息

 

see

https://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html

 

原文见

https://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html

 

--------------------------------------------

 

Objects, Classes, and Messaging

 

对象,类和消息

 

This chapter describes the fundamentals of objects, classes, and messaging as used and implemented by the Objective-C language. It also introduces the Objective-C runtime.

 

本章描述被Objective-C语言使用和实现的对象,类和消息的基础。它还介绍Objective-C运行时。

 

--------------------------------------------

 

The Runtime System

 

运行时系统

 

The Objective-C language defers as many decisions as it can from compile time and link time to runtime. Whenever possible, it dynamically performs operations such as creating objects and determining what method to invoke. Therefore, the language requires not just a compiler, but also a runtime system to execute the compiled code. The runtime system acts as a kind of operating system for the Objective-C language; it’s what makes the language work. Typically, however, you don’t need to interact with the runtime directly. To understand more about the functionality it offers, though, see Objective-C Runtime Programming Guide.

 

Objective-C语言从编译期和链接期中延迟它尽可能多的决定到运行期。在任何可以的时候,它都会动态地执行操作诸如创建对象和决定调用什么方法。因此,语言不仅仅需要一个编译器,还需要一个运行时系统以执行被编译的代码。运行时系统的作用如同一种用于Objective-C语言的操作系统;这是使语言工作的东西。然而典型地,你将不需要直接与运行时交互。尽管如此,为了理解关于它提供功能的更多信息,参阅Objective-C运行时编程指南。

 

--------------------------------------------

 

Objects

 

对象

 

As the name implies, object-oriented programs are built around objects. An object associates data with the particular operations that can use or affect that data. Objective-C provides a data type to identify an object variable without specifying a particular class of the object.

 

顾名思义,面向对象编程是围绕对象来构建的。一个对象与数据关联,它带有可以使用和影响那个对象的特定操作。Objective-C提供一种数据类型以标识一个对象变量而不需要指定对象的一个特定类。

 

Object Basics

 

对象基础

 

An object associates data with the particular operations that can use or affect that data. In Objective-C, these operations are known as the object’s methods; the data they affect are its instance variables (in other environments they may be referred to as ivars or member variables). In essence, an object bundles a data structure (instance variables) and a group of procedures (methods) into a self-contained programming unit.

 

一个对象关联着一些带有可使用或影响那个数据的特定操作。在Objective-C中,这些操作被称为对象的方法;它们影响的数据是它的实例变量(在其它环境它们可能被称为ivar或成员变量)。本质上,一个对象把一个数据结构(实例变量)以及一组过程(方法)捆绑进一个独立的编程单元。

 

In Objective-C, an object’s instance variables are internal to the object; generally, you get access to an object’s state only through the object’s methods (you can specify whether subclasses or other objects can access instance variables directly by using scope directives, see “The Scope of Instance Variables”). For others to find out something about an object, there has to be a method to supply the information. For example, a rectangle would have methods that reveal its size and position.

 

在Objective-C中,一个对象的实例变量对于对象来说是内部的;通常,你只通过对象的方法访问一个对象的状态(你可以通过作用域指示符指定子类或其它对象是否可以直接地访问实例变量,见“实例变量的作用域”)。为了让其它对象知道关于一个对象的一些事情,必须有一个方法来提供信息。例如,一个矩形将拥有展示它的大小和位置的方法。

 

Moreover, an object sees only the methods that were designed for it; it can’t mistakenly perform methods intended for other types of objects. Just as a C function protects its local variables, hiding them from the rest of the program, an object hides both its instance variables and its method implementations.

 

此外,一个对象只看到为它而设计的方法;它无法错误地执行打算用于其它类型的对象的方法。正如一个C函数通过对程序的其它部分隐藏掉它的局部变量来保护它们那样,一个对象同时隐藏它的实例变量和它的方法实现。

 

id

 

id类型

 

In Objective-C, object identifiers are of a distinct data type: id. This type is the general type for any kind of object regardless of class and can be used for instances of a class and for class objects themselves.

 

在Objective-C中,对象标识符属于一个独特的数据类型:id。这个类型是通用类型,用于任意类型的对象,不管类是什么,并且可以被用于一个类的实例和类对象自身。

 

--------------------------------------------

 

id anObject;

 

--------------------------------------------

 

For the object-oriented constructs of Objective-C, such as method return values, id replaces int as the default data type. (For strictly C constructs, such as function return values, int remains the default type.)

 

对于Objective-C的面向对象构造式,诸如方法返回值,id取代int作为默认的数据类型。(注:传统C语言可以省略返回值的类型,缺省为int)(对于严谨的C构造式,诸如函数返回值,int依然是默认类型。)

 

The keyword nil is defined as a null object, an id with a value of 0. id, nil, and the other basic types of Objective-C are defined in the header file objc/objc.h.

 

关键词nil被定义为一个空对象,一个值为0的id。id,nil,以及Objective-C的其它基本类型被定义在头文件objc/objc.h中。

 

id is defined as pointer to an object data structure:

 

id被定义为指向一个对象数据结构体的指针:

 

--------------------------------------------

 

typedef struct objc_object {

    Class isa;

} *id;

 

--------------------------------------------

 

Every object thus has an isa variable that tells it of what class it is an instance. Since the Class type is itself defined as a pointer:

 

因此,每个对象拥有一个isa变量,它告诉对象它是一个什么类的实例。因为Class类型是它自己,而它被定义为一个指针。

 

--------------------------------------------

 

typedef struct objc_class *Class;

 

--------------------------------------------

 

the isa variable is frequently referred to as the “isa pointer.”

 

isa变量经常被称为“isa指针”。(注:is a的缩写,意思是“是一个……”)

 

Dynamic Typing

 

动态类型

 

The id type is completely nonrestrictive. By itself, it yields no information about an object, except that it is an object. At some point, a program typically needs to find more specific information about the objects it contains. Since the id type designator can’t supply this specific information to the compiler, each object has to be able to supply it at runtime.

 

id类型完全是非限制性的。通过它自身,它不产生关于一个对象的信息,除了它是一个对象。在一些点上,一个程序动态地需要找到关于它包含对象的更多特定信息。因为id类型指定者不能提供这个指定信息给编译器,所以每个对象必须能够在运行期提供这个信息。

 

The isa instance variable identifies the object’s class—what kind of object it is. Objects with the same behavior (methods) and the same kinds of data (instance variables) are members of the same class.

 

isa实例变量标识对象的类——它是什么类型的对象。带有相同行为(方法)和相同类型数据(实例变量)的对象是相同类的成员。

 

Objects are thus dynamically typed at runtime. Whenever it needs to, the runtime system can find the exact class that an object belongs to, just by asking the object. (To learn more about the runtime, see Objective-C Runtime Programming Guide.) Dynamic typing in Objective-C serves as the foundation for dynamic binding, discussed later.

 

因此对象在运行期动态地被类型化。每当它需要时,运行时系统可以找到一个对象所属的具体类,只要通过询问对象即可。(要想知道关于运行时的更多信息,见Objective-C运行时编程指南)。在Objective-C中动态类型担当动态绑定的基础,稍后会讨论它。

 

The isa variable also enables objects to perform introspection—to find out about themselves (or other objects). The compiler records information about class definitions in data structures for the runtime system to use. The functions of the runtime system use isa to find this information at runtime. Using the runtime system, you can, for example, determine whether an object implements a particular method or discover the name of its superclass.

 

isa变量还使对象能执行自省——以了解他们自身(或其它对象)。编译器在数据结构中记录关于类定义的信息以提供给运行时系统使用。运行时系统的函数在运行期使用isa来找到这个信息。使用运行时系统,你可以,例如,决定一个对象是否实现一个特定方法或发现它的超类的名称。

 

Object classes are discussed in more detail under “Classes.”

 

在“类”中会更详细地讨论对象的类。

 

It’s also possible to give the compiler information about the class of an object by statically typing it in source code using the class name. Classes are particular kinds of objects, and the class name can serve as a type name. See “Class Types” and “Enabling Static Behavior.”

 

还可以通过在源代码中使用类名静态类型化它,给予编译器关于一个对象的类的信息,类是特殊类型的对象,而类名可以担当一个类型名。参见“类类型”和“使能静态行为”。

 

Memory Management

 

内存管理

 

In any program, it is important to ensure that objects are deallocated when they are no longer needed—otherwise your application’s memory footprint becomes larger than necessary. It is also important to ensure that you do not deallocate objects while they’re still being used.

 

在任意程序中,重要的是确保对象在它们不再被需要时被释放——否则你的应用程序的内存足迹变得比需要的大。还有重要的是确保你当对象仍然被使用时不释放它们。

 

Objective-C offers three mechanisms for memory management that allow you to meet these goals:

 

Objective-C提供允许你满足这些目标的三种内存管理机制:

 

* Automatic Reference Counting (ARC), where the compiler reasons about the lifetimes of objects.

 

* 自动引用计数(ARC),在这里编译器推断对象的生命期。

 

* Manual Reference Counting (MRC, sometimes referred to as MRR for “manual retain/release”), where you are ultimately responsible for determining the lifetime of objects.

 

* 手动引用计数(MRC,有时被称为MRR,代表“手动维持/释放”)。在这里你最终负责决定对象的生命期。

 

Manual reference counting is described in Advanced Memory Management Programming Guide.

 

手动引用计数在高级内存管理编程指南中被描述。

 

* Garbage collection, where you pass responsibility for determining the lifetime of objects to an automatic “collector.”

 

* 垃圾回收,在那里你把决定对象生命期的责任交给一个自动“回收器”。

 

Garbage collection is described in Garbage Collection Programming Guide. (Not available for iOS—you cannot access this document through the iOS Dev Center.)

 

垃圾回收在垃圾回收编程指南中被描述。(对于iOS来说是不可用的——你无法通过iOS开发中心访问到这篇文档。)

 

--------------------------------------------

 

Object Messaging

 

对象消息

 

This section explains the syntax of sending messages, including how you can nest message expressions. It also discusses the scope or “visibility” of an object’s instance variables, and the concepts of polymorphism and dynamic binding.

 

本章节解释发送消息的语法,包括你如何可以嵌套消息表达式。它还讨论一个对象的实体变量的“可视性”范围,以及多态与动态绑定的概念。

 

Message Syntax

 

消息语法

 

To get an object to do something, you send it a message telling it to apply a method. In Objective-C, message expressions are enclosed in brackets:

 

为了让一个对象做某些事情,你发送它一个消息告诉它去应用一个方法。在Objective-C中,消息表达式是被封闭在方括号中的:

 

--------------------------------------------

 

[receiver message]

 

--------------------------------------------

 

The receiver is an object, and the message tells it what to do. In source code, the message is simply the name of a method and any parameters that are passed to it. When a message is sent, the runtime system selects the appropriate method from the receiver’s repertoire and invokes it.

 

receiver是一个对象,而message告诉它做什么。在源代码中,消息简单地是一个方法名以及任意被传递给它的参数。当一个消息被发送时,运行时系统从接收者的指令表中选择合适的方法并且调用它。

 

For example, this message tells the myRectangle object to perform its display method, which causes the rectangle to display itself:

 

例如,这个消息告诉myRectangle对象去执行它的display方法,这导致该矩形显示它自身。

 

--------------------------------------------

 

[myRectangle display];

 

--------------------------------------------

 

The message is followed by a “;” as is normal for any statement in C.

 

消息后面跟随着一个“;”(注:分号),这对于C中的任意语句来说是正常。

 

Because the method name in a message serves to “select” a method implementation, method names in messages are often referred to as selectors.

 

因为在消息中方法名担当“选择”一个方法实现的作用,所以在消息中方法名常常被引用作为选择器。

 

Methods can also take parameters, sometimes called arguments. A message with a single parameter affixes a colon (:) to the name and puts the parameter right after the colon:

 

方法还可以持有参数,它有时被称为argument(注:在中文中parameter和argument没有区别,但在科学领域中parameter比较正式。我觉得在这里parameter应该是特指objc中冒号格式的参数,而argument特指C中的参数)。一个单一参数附着一个冒号(:)到名称并正好把参数放置在冒号后面:

 

--------------------------------------------

 

[myRectangle setWidth:20.0];

 

--------------------------------------------

 

For methods with multiple parameters, Objective-C's method names are interleaved with the parameters such that the method’s name naturally describes the parameters expected by the method. The imaginary message below tells the myRectangle object to set its origin to the coordinates (30.0, 50.0):

 

对于使用多参数的方法,Objective-C的方法名用参数交错开来,以使方法名自然地描述方法所期待的参数。下面假设的消息告诉myRectangle去设置它的原地到坐标(30.0, 50.0):

 

--------------------------------------------

 

[myRectangle setOriginX: 30.0 y: 50.0]; // This is a good example of

                                        // multiple parameters

                                        // 这是多参数的一个好示例

 

--------------------------------------------

 

A selector name includes all the parts of the name, including the colons, so the selector in the preceding example is named setOriginX:y:. It has two colons, because it takes two parameters. The selector name does not, however, include anything else, such as return type or parameter types.

 

一个选择器名称包括名称的所有部分,包括冒号,所以在前面的示例中选择器被命名为setOriginX:y:。它拥有两个冒号,因为它持有两个参数。然而,选择器的名称不包括其它任意东西,诸如返回类型或参数类型。

 

--------------------------------------------

 

Important The subparts of an Objective-C selector name are not optional, nor can their order be varied. In some languages, the terms “named parameters” and “keyword parameters” carry the implications that the parameters can vary at runtime, can have default values, can be in a different order, and can possibly have additional named parameters. None of these characteristics about parameters are true for Objective-C.

 

重要:一个Objective-C选择器名称的子部分既不是可选的,它们的顺序也不可以被改变。在一些语言中,术语“具名参数”和“关键词参数”带有参数可以在运行时改变的暗示,可以拥有默认值,可以以一个不同的顺序,而且可能可以拥有额外的具名参数。这些关于参数的特性对于Objective-C都不成立。

 

For all intents and purposes, an Objective-C method declaration is simply a C function that prepends two additional parameters (see “Messaging” in the Objective-C Runtime Programming Guide). Thus, the structure of an Objective-C method declaration differs from the structure of a method that uses named or keyword parameters in a language like Python, as the following Python example illustrates:

 

为了所有意图和目的,一个Objective-C方法的声明简单地是一个前接两个额外参数的C函数(见Objective-C运行时编程指引中的“消息”)(注:[receiver message]等效于objc_msgSend(receiver, selector, arg1, arg2, ...),receiver和selector是两个隐藏的参数,详细请见https://developer.apple.com/library/mac/#documentation/cocoa/conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html#//apple_ref/doc/uid/TP40008048-CH104)。这样,一个Objective-C方法不同于一个在像Python的语言中使用具名或关键词参数的方法的结构,正如下面的Python示例中所表示的:

 

--------------------------------------------

 

def func(a, b, NeatMode=SuperNeat, Thing=DefaultThing):

    pass

 

--------------------------------------------

 

In this Python example, Thing and NeatMode might be omitted or might have different values when called.

 

在这个Python示例中,Thing和NeatMode在被调用时可能被忽略或者可能拥有不同的值。

 

--------------------------------------------

 

In principle, a Rectangle class could instead implement a setOrigin:: method with no label for the second parameter, which would be invoked as follows:

 

原则上,一个Rectangle类可以改为实现一个setOrigin::方法,对于第二参数来说它不带标签,这将如下所示被调用:

 

--------------------------------------------

 

[myRectangle setOrigin:30.0 :50.0]; // This is a bad example of multiple parameters

 

[myRectangle setOrigin:30.0 :50.0]; // 这是多参数的一个坏示例

 

--------------------------------------------

 

While syntactically legal, setOrigin:: does not interleave the method name with the parameters. Thus, the second parameter is effectively unlabeled and it is difficult for a reader of this code to determine the kind or purpose of the method’s parameters.

 

虽然句法上是合法的,但setOrigin::并没有用参数交错开方法名。因此,第二参数是有效地被取消标签,并且它难以让这段代码的阅读者确定该方法的参数的目的。

 

Methods that take a variable number of parameters are also possible, though they’re somewhat rare. Extra parameters are separated by commas after the end of the method name. (Unlike colons, the commas are not considered part of the name.) In the following example, the imaginary makeGroup: method is passed one required parameter (group) and three parameters that are optional:

 

持有不同数量参数的方法也是可能的,虽然他们有点罕见。额外参数通过方法名称结束处后面的逗号来分隔开。(不像冒号那样,逗号不被认为是名称的一部分。)在以下示例中,假设的makeGroup:方法被传递进一个必需的参数(group)和三个可选的参数:

 

--------------------------------------------

 

[receiver makeGroup:group, memberOne, memberTwo, memberThree];

 

--------------------------------------------

 

Like standard C functions, methods can return values. The following example sets the variable isFilled to YES if myRectangle is drawn as a solid rectangle, or NO if it’s drawn in outline form only.

 

想标准C函数那样,方法可以返回值,以下示例设置变量isFilled为YES,如果myRectangle被绘画作为一个实矩形,或者NO如果它只是被绘画成轮廓形式。

 

--------------------------------------------

 

BOOL isFilled;

isFilled = [myRectangle isFilled];

 

--------------------------------------------

 

Note that a variable and a method can have the same name.

 

注意一个变量和一个方法可以拥有相同名称。

 

One message expression can be nested inside another. Here, the color of one rectangle is set to the color of another:

 

一个消息表达式可以被嵌套在另一个里面。这里,一个矩形的颜色被设置为另一个矩形的颜色:

 

--------------------------------------------

 

[myRectangle setPrimaryColor:[otherRect primaryColor]];

 

--------------------------------------------

 

Objective-C also provides a dot (.) operator that offers a compact and convenient syntax for invoking an object’s accessor methods. The dot operator is often used in conjunction with the declared properties feature (see “Declared Properties”) and is described in “Dot Syntax.”

 

Objective-C还提供一个点(.)操作符,它为调用一个对象的访问器方法提供一个紧凑和便利的语法。点号操作符常常与被声明属性特性组合使用(见“被声明属性”)并且以“点语法”来描述。

 

Sending Messages to nil

 

发送消息至nil

 

In Objective-C, it is valid to send a message to nil—it simply has no effect at runtime. There are several patterns in Cocoa that take advantage of this fact. The value returned from a message to nil may also be valid:

 

在Objective-C中,发送一个消息至nil是有效的——它简单地不影响运行期。在Cocoa中有几种模式利用这个事实。从一个消息返回到nil的值也可以是有效的:

 

* If the method returns an object, then a message sent to nil returns 0 (nil). For example:

 

* 如果方法返回一个对象,那么发送给nil的消息返回0(nil),例如:

 

--------------------------------------------

 

Person *motherInLaw = [[aPerson spouse] mother];

 

--------------------------------------------

 

If the spouse object here is nil, then mother is sent to nil and the method returns nil.

 

如果这里的配偶(注:aPerson的配偶)对象是nil,那么mother被发送到nil并且该方法返回nil。

 

* If the method returns any pointer type, any integer scalar of size less than or equal to sizeof(void*), a float, a double, a long double, or a long long, then a message sent to nil returns 0.

 

* 如果方法返回任意指针类型,大小小于或等于sizeof(void*)的任意整型标量,一个float型,一个double型,一个long double型,或一个long long型,那么发送给nil的消息返回0.

 

* If the method returns a struct, as defined by the Mac OS X ABI Function Call Guide to be returned in registers, then a message sent to nil returns 0.0 for every field in the struct. Other struct data types will not be filled with zeros.

 

* 如果该方法返回一个结构体,正如Mac OS ABI函数调用指引所定义的在寄存器中返回,那么一个发送到nil的消息对于结构体中每个域返回0.0。其它结构体数据类型将不使用零来填充。

 

* If the method returns anything other than the aforementioned value types, the return value of a message sent to nil is undefined.

 

* 如果该方法返回任意东西而非上述的值类型,那么一个发送到nil的消息的返回值是未定义的。

 

The following code fragment illustrates a valid use of sending a message to nil.

 

以下代码片段描述发送一个消息到nil的一个有效使用。

 

--------------------------------------------

 

id anObjectMaybeNil = nil;

 

// this is valid

// 这是有效的

if ([anObjectMaybeNil methodThatReturnsADouble] == 0.0)

{

    // implementation continues...

    // 实现继续……

}

 

--------------------------------------------

 

The Receiver’s Instance Variables

 

接收者的实例变量

 

A method has automatic access to the receiving object’s instance variables. You don’t need to pass them to the method as parameters. For example, the primaryColor method illustrated above takes no parameters, yet it can find the primary color for otherRect and return it. Every method assumes the receiver and its instance variables, without having to declare them as parameters.

 

一个方法拥有对接收对象的实例变量的自动访问权。你不需要传递它们到方法作为参数。例如,上面展示的primaryColor方法不带参数,但是它可以为otherRect找到主颜色并返回它。每个方法假设接收器和它的实例变量,不必声明它们作为参数。

 

This convention simplifies Objective-C source code. It also supports the way object-oriented programmers think about objects and messages. Messages are sent to receivers much as letters are delivered to your home. Message parameters bring information from the outside to the receiver; they don’t need to bring the receiver to itself.

 

这个约定简化Objective-C源代码,它还支持面向对象程序员考虑对象和消息的方式。消息被发送到接收者,非常像被邮递到你家的信件。消息参数从外面把信息带给接收者;它们不需要把接收者带给自己。

 

A method has automatic access only to the receiver’s instance variables. If it requires information about a variable stored in another object, it must send a message to the object asking it to reveal the contents of the variable. The primaryColor and isFilled methods shown earlier are used for just this purpose.

 

一个方法拥有只对接收者的实例变量的自动访问权。如果它需要关于一个存储在另一个对象中的变量的信息,它必须发送一个消息给该对象,叫它展示该变量的内容。前面展示的primaryColor和isFilled方法正好被用于此目的。

 

See “Defining a Class” for more information on referring to instance variables.

 

参见“定义一个类”以获得关于对实例变量的引用的更多信息。

 

Polymorphism

 

多态

 

As the earlier examples illustrate, messages in Objective-C appear in the same syntactic positions as function calls in standard C. But, because methods “belong to” an object, messages don’t behave in the same way that function calls do.

 

正如前面的示例所示,在Objective-C中消息出现在相同的句法位置,正如在标准C中的函数调用。但是,因为方法“属于”一个对象,所以消息并不依照函数调用的相同方式行为。

 

In particular, an object can be operated on by only those methods that were defined for it. It can’t confuse them with methods defined for other kinds of object, even if another object has a method with the same name. Therefore, two objects can respond differently to the same message. For example, each kind of object that receives a display message could display itself in a unique way. A Circle and a Rectangle would respond differently to identical instructions to track the cursor.

 

特别地,一个对象可以只被那些为它而定义的那些方法所操作。不能用为其它类型的对象而定义的方法来混淆它们,即便另一个对象拥有使用相同名称的一个方法。因此,两个对象可以不同地响应相同的消息。例如,接收一个display消息的每类对象可以以一种唯一的方式来显示它自身。一个Circle和一个Rectangle将不同地响应相同的指令以追踪鼠标。

 

This feature, referred to as polymorphism, plays a significant role in the design of object-oriented programs. Together with dynamic binding, it permits you to write code that might apply to any number of different kinds of objects, without you having to choose at the time you write the code what kinds of objects they might be. They might even be objects that will be developed later, by other programmers working on other projects. If you write code that sends a display message to an id variable, any object that has a display method is a potential receiver.

 

此特性,被称为多态,在面向对象编程中扮演重要的作用。与动态绑定一起,它允许你编写可能应用到任意数量不同类型的对象的代码,而你不必在你编写代码的时候选择它们可能是什么类型的对象。它们甚至可能较迟地由工作在其它工程上的其他程序员开发的对象。如果你编写发送一个display消息到一个id变量的代码,任意拥有一个display方法的对象是一个隐式的接收者。

 

Dynamic Binding

 

动态绑定

 

A crucial difference between function calls and messages is that a function and its parameters are joined together in the compiled code, but a message and a receiving object aren’t united until the program is running and the message is sent. Therefore, the exact method invoked to respond to a message can be determined only at runtime, not when the code is compiled.

 

在调用和消息之间一个重要的不同是,一个函数和它的参数在被编译的代码中被连接在一起,但一个消息和一个接收对象不被组合,直至程序正在运行并且消息被发送。因此,被调用以响应一个消息的具体方法只可以在运行时确定,而非在代码被编译时。

 

When a message is sent, a runtime messaging routine looks at the receiver and at the method named in the message. It locates the receiver’s implementation of a method matching the name, “calls” the method, and passes it a pointer to the receiver’s instance variables. (For more on this routine, see “Messaging” in Objective-C Runtime Programming Guide.)

 

当一个消息被发送时,一个运行时消息例行程序查看接收者并且查看在消息中命名的方法。它定位一个匹配该方法的接收者实现,“调用”该方法,并且传递它一个指针到该接收者的实例变量。(关于这个例行程序的更多内容,参考在Objective-C运行时编程指南中的“消息”)。

 

This dynamic binding of methods to messages works hand in hand with polymorphism to give object-oriented programming much of its flexibility and power. Because each object can have its own version of a method, an Objective-C statement can achieve a variety of results, not by varying the message but by varying the object that receives the message. Receivers can be decided as the program runs; the choice of receiver can be made dependent on factors such as user actions.

 

这个方法对消息的动态绑定用多态来联合地工作,以给予面向对象编程它的很多灵活性和力量。因为每个对象可以拥有一个方法的它自己的版本,所以一个Objective-C语句可以达到多种结果,不是通过改变消息而是通过接收消息的对象。接收者可以在程序运行时确定;可以让接收者的选择依赖于一些事实如用户动作。

 

When executing code based upon the Application Kit (AppKit), for example, users determine which objects receive messages from menu commands such as Cut, Copy, and Paste. The message goes to whatever object controls the current selection. An object that displays text would react to a copy message differently from an object that displays scanned images. An object that represents a set of shapes would respond differently to a copy message than a Rectangle would. Because messages do not select methods until runtime (from another perspective, because binding of methods to messages does not occur until runtime), these differences in behavior are isolated to the methods themselves. The code that sends the message doesn’t have to be concerned with them; it doesn’t even have to enumerate the possibilities. An application’s objects can each respond in its own way to copy messages.

 

例如,当执行基于应用程序工具箱(AppKit)(注:Cocoa有两个核心框架,Foundation和Application Kit框架。详细请见http://www.apple.com.cn/developer/mac/library/documentation/Cocoa/Conceptual/CocoaFundamentals/WhatIsCocoa/chapter_2_section_5.html)的代码时,用户从菜单命令诸如剪切、复制和粘贴中决定哪些对象接收消息。消息发送至控制当前选择的不管哪个对象。一个代表一组形状的对象对一个copy消息所作出的响应不同于一个Rectangle将作出的响应。因为消息直至运行时才选择方法(从另一个观点看,因为方法到消息的绑定直至运行时才发生),这些在行为上的区别从方法自身隔离开。发送消息的代码不必干预它们;它甚至不必列举可能性。一个应用程序的多个对象可以以它自己的方式来响应copy消息。

 

Objective-C takes dynamic binding one step further and allows even the message that’s sent (the method selector) to be a variable determined at runtime. This mechanism is discussed in the section “Messaging” in Objective-C Runtime Programming Guide.

 

Objective-C让动态绑定更进一步,甚至允许被发送的消息(方法选择器)是一个在运行时决定的变量。这种机制在Objective-C运行时编程指南中的“消息”章节中讨论。

 

Dynamic Method Resolution

 

动态方法解析

 

You can provide implementations of class and instance methods at runtime using dynamic method resolution. See “Dynamic Method Resolution” in Objective-C Runtime Programming Guide for more details.

 

你可以在运行期使用动态方法解析来提供类的实现和实例方法。参考Objective-C运行时编程指南中的“动态方法解析”以获得更多细节。

 

Dot Syntax

 

点语法

 

Objective-C provides a dot (.) operator that offers an alternative to square bracket notation ([]) to invoke accessor methods. Dot syntax uses the same pattern that accessing C structure elements uses:

 

Objective-C提供一个点(.)操作符,它提供一个方括号符号([])的选择方案以调用访问器方法。点语法使用访问C结构体元素的相同模式。

 

--------------------------------------------

 

myInstance.value = 10;

printf("myInstance value: %d", myInstance.value);

 

--------------------------------------------

 

When used with objects, however, dot syntax acts as “syntactic sugar”—it is transformed by the compiler into an invocation of an accessor method. Dot syntax does not directly get or set an instance variable. The code example above is exactly equivalent to the following:

 

然而,当用于对象时,点语法扮演“语法糖”的作用——它被编译器转换为一个访问器方法的一次调用。点语法不直接获取或设置一个实例变量。上面的代码示例完全等效于以下:

 

--------------------------------------------

 

[myInstance setValue:10];

printf("myInstance value: %d", [myInstance value]);

 

--------------------------------------------

 

As a corollary, if you want to access an object’s own instance variable using accessor methods, you must explicitly call out self, for example:

 

作为推论,如果你想使用访问器方法访问一个对象自己的实例变量,你必须显式地调用self,例如,

 

--------------------------------------------

 

self.age = 10;

 

--------------------------------------------

 

or the equivalent:

 

或者等效物:

 

--------------------------------------------

 

[self setAge:10];

 

--------------------------------------------

 

If you do not use self., you access the instance variable directly. In the following example, the set accessor method for age is not invoked:

 

如果你不使用self.,那么你直接访问实例变量。在以下示例中,age的set访问器方法不被调用:

 

--------------------------------------------

 

age = 10;

 

--------------------------------------------

 

If a nil value is encountered during property traversal, the result is the same as sending the equivalent message to nil. For example, the following pairs are all equivalent:

 

如果在属性跨越(注:应该是指点操作链)期间遇到一个nil值,那么结果和发送等效的消息到nil的结果相同。例如,以下配对都是等效的。

 

--------------------------------------------

 

// Each member of the path is an object.

// 路径的每个成员都是一个等效。

x = person.address.street.name;

x = [[[person address] street] name];

 

// The path contains a C struct.

// This will crash if window is nil or -contentView returns nil.

// 路径包含一个C结构体

// 这将崩溃如果window是nil或-contentView返回一个nil

y = window.contentView.bounds.origin.y;

y = [[window contentView] bounds].origin.y;

 

// An example of using a setter.

// 使用一个set方法的示例

person.address.street.name = @"Oxford Road";

[[[person address] street] setName: @"Oxford Road"];

 

--------------------------------------------

 

--------------------------------------------

 

Classes

 

 

An object-oriented program is typically built from a variety of objects. A program based on the Cocoa frameworks might use NSMatrix objects, NSWindow objects, NSDictionary objects, NSFont objects, NSText objects, and many others. Programs often use more than one object of the same kind or class—several NSArray objects or NSWindow objects, for example.

 

一个面向等效编程典型地从不同类型的对象中构建。一个基于Cocoa框架的程序可能使用NSMatrix对象,NSWindow对象,NSDictionary对象,NSFont对象,NSText对象,以及其它许多对象。程序常常使用相同类型或类的多于一个对象——例如,几个NSArray对象或NSWindow对象。

 

In Objective-C, you define objects by defining their class. The class definition is a prototype for a kind of object; it declares the instance variables that become part of every member of the class, and it defines a set of methods that all objects in the class can use.

 

在Objective-C中,你通过定义它们的类来定义对象。类定义是用于一类对象的一个原型;它声明实例变量,它成为类的每个成员(注:实例?)的一部分,而且它定义一组方法,该类内的所有对象都可以使用它们。

 

The compiler creates just one accessible object for each class, a class object that knows how to build new objects belonging to the class. (For this reason it’s traditionally called a factory object.) The class object is the compiled version of the class; the objects it builds are instances of the class. The objects that do the main work of your program are instances created by the class object at runtime.

 

编译器只为每个类创建一个可访问的对象,一个类对象,它知道如何构建属于该类的新对象。(因此它传统上被称为工厂对象)。类对象是类的被编译版本;它构建的对象是类的实例。执行你的程序的主要工作的对象是在运行时被类对象创建的实例。

 

All instances of a class have the same set of methods, and they all have a set of instance variables cut from the same mold. Each object gets its own instance variables, but the methods are shared.

 

一个类的所有实例拥有相同的方法集合,而且它们全都拥有从相同的模子中剪出来的一组实例变量。每个对象获取它自己的实例变量,但方法是共享的。

 

By convention, class names begin with an uppercase letter (such as Rectangle); the names of instances typically begin with a lowercase letter (such as myRectangle).

 

约定下,类的名称以一个大写字母开头(诸如Rectangle);实例的名称通常以一个小写字母开头(诸如myRectangle)。

 

Inheritance

 

继承

 

Class definitions are additive; each new class that you define is based on another class from which it inherits methods and instance variables. The new class simply adds to or modifies what it inherits. It doesn’t need to duplicate inherited code.

 

类定义是添加的;你定义的每个新类是基于另一个类,从它那里继承方法和实例变量。新类简单地添加到或修改它所继承的东西。它不需要复制被继承的代码。

 

Inheritance links all classes together in a hierarchical tree with a single class at its root. When writing code that is based upon the Foundation framework, that root class is typically NSObject. Every class (except a root class) has a superclass one step nearer the root, and any class (including a root class) can be the superclass for any number of subclasses one step farther from the root. Figure 1-1 illustrates the hierarchy for a few of the classes used in a drawing program.

 

继承链接所有类一起在一个等级树,在它的根有一个单一类。当编写基于Foundation框架的代码时,那个根类通常是NSObject。每个类(除了根类)拥有一个距离根更近一步的超类,而且任意类(包括根类)可以是距离根更远一步的任意数量子类的超类。图1-1描绘在绘画程序中使用的一些类的等级。

 

--------------------------------------------

 

Figure 1-1  Some drawing program classes

 

图1-1 一些绘画程序的类

 

 

(图略:

NSObject -> Graphic -> Image

                    -> Text

                    -> Shape -> Line

                             -> Rectangle -> Square

                             -> Circle

 

--------------------------------------------

 

Figure 1-1 shows that the Square class is a subclass of the Rectangle class, the Rectangle class is a subclass of Shape, Shape is a subclass of Graphic, and Graphic is a subclass of NSObject. Inheritance is cumulative. So a Square object has the methods and instance variables defined for Rectangle, Shape, Graphic, and NSObject, as well as those defined specifically for Square. This is simply to say that an object of type Square isn’t only a square, it’s also a rectangle, a shape, a graphic, and an object of type NSObject.

 

图1-1展示Square类是Rectangle类的一个子类,Rectangle类是Shape的一个子类,Shape是Graphic的一个子类,而Graphic是NSObject的一个子类。继承是累积的。所以一个Square对象拥有为Rectangle,Shape,Graphic,和NSObject而定义的方法和实例变量,以及特定为Square而定义的那些方法和实例变量。这简单来说就是一个类型为Square的对象不只是一个正方形,它还是一个矩形,一个形状,一个图形,和一个类型为NSObject的对象。

 

Every class but NSObject can thus be seen as a specialization or an adaptation of another class. Each successive subclass further modifies the cumulative total of what’s inherited. The Square class defines only the minimum needed to turn a rectangle into a square.

 

因此每个类除了NSObject可以被看到作为另一个类的一个特殊化或一个改编。每个连续子类进一步修改继承东西的累积总和。Square类只定义让一个矩形变成正方形所需要的最小化。

 

When you define a class, you link it to the hierarchy by declaring its superclass; every class you create must be the subclass of another class (unless you define a new root class). Plenty of potential superclasses are available. Cocoa includes the NSObject class and several frameworks containing definitions for more than 250 additional classes. Some are classes that you can use off the shelf and incorporate them into your program as is. Others you might want to adapt to your own needs by defining a subclass.

 

当你定义一个类时,你通过它的超类链接它到等级;你创建的每个类必须是另一个类的子类(除非你定义一个新的根类)。许多隐式子类是有效的。Cocoa包含NSObject类和用于多于250个附加类的几个框架包含定义。一些是你不用定制就可以使用的类并且不作修改就组合它们进你的程序。另一些你可能想通过定义一个子类来适配你自己的需要。

 

Some framework classes define almost everything you need, but leave some specifics to be implemented in a subclass. You can thus create very sophisticated objects by writing only a small amount of code and reusing work done by the programmers of the framework.

 

一些框架类定义你需要的几乎所有东西,但在子类中留下一些要实现的细节。因此你可以通过只编写一段小量的代码并重用框架程序员所完成的工作来创建非常复杂的对象。

 

The NSObject Class

 

NSObject类

 

NSObject is a root class, and so doesn’t have a superclass. It defines the basic framework for Objective-C objects and object interactions. It imparts to the classes and instances of classes that inherit from it the ability to behave as objects and cooperate with the runtime system.

 

NSObject是一个根类,所以它没有超类。它为Objective-C对象和对象交互定义基本的框架。它告知类和类实例从它继承作为对象地行为以及与运行时系统协作的能力。

 

A class that doesn’t need to inherit any special behavior from another class should nevertheless be made a subclass of the NSObject class. Instances of the class must at least have the ability to behave like Objective-C objects at runtime. Inheriting this ability from the NSObject class is much simpler and much more reliable than reinventing it in a new class definition.

 

一个不需要从另一个类中继承任何特殊行为的类仍然应该作为NSObject类的一个子类。该类的实例必须至少在运行时中拥有像Objective-C对象的行为的能力。从NSObject类中继承这种能力比在一个新类定义中重新发明它更简单和更可靠多了。

 

--------------------------------------------

 

Note: Implementing a new root class is a delicate task and one with many hidden hazards. The class must duplicate much of what the NSObject class does, such as allocate instances, connect them to their class, and identify them to the runtime system. For this reason, you should generally use the NSObject class provided with Cocoa as the root class. For more information, see NSObject Class Reference and the NSObject Protocol Reference.

 

注意:实现一个新的根类是一件精密的任务而且它带有许多隐藏的危险。该类必须复制NSObject类所做的很多事情,诸如分配实例,连接它们到它们的类,以及标识它们到运行时系统。因此,你通常应该使用Cocoa提供的NSObject作为根类。想获得更多信息,参考NSObject类参考文档和NSObject协议参考文档。

 

--------------------------------------------

 

Inheriting Instance Variables

 

继承实例变量

 

When a class object creates a new instance, the new object contains not only the instance variables that were defined for its class but also the instance variables defined for its superclass and for its superclass’s superclass, all the way back to the root class. Thus, the isa instance variable defined in the NSObject class becomes part of every object. isa connects each object to its class.

 

当一个类对象创建一个新实例时,新对象不只是包含为它的类而定义实例变量,还包含为它的超类和为它的超类的超类定义的实例变量,一直向上到根类。因此,在NSObject类中定义的isa实例变量称为每一个对象的一部分。isa连接每个对象到它的类。

 

Figure 1-2 shows some of the instance variables that could be defined for a particular implementation of a Rectangle class and where they may come from. Note that the variables that make the object a rectangle are added to the ones that make it a shape, and the ones that make it a shape are added to the ones that make it a graphic, and so on.

 

图1-2展示一些实例变量,它们可能为一个Rectangle类的一个特殊实现和它们可能来自于的地方而定义的。注意让对象变成一个矩形的变量被添加到让它成为一个形状的变量,而让它成为一个形状的变量被添加到让它成为一个图形的变量,如此类推。

 

--------------------------------------------

 

Figure 1-2  Rectangle instance variables

 

图1-2 Rectangle实例变量

 

(图略:

Class isa; //在NSObject中声明

NSPoint orign; //在Graphic中声明

NSColor *primaryColor; //在Shape中声明

Pattern linePattern;

...

float width; //在Rectangle中声明

float height;

BOOL filled;

NSColor *fillColor;

 

--------------------------------------------

 

A class doesn’t have to declare instance variables. It can simply define new methods and rely on the instance variables it inherits, if it needs any instance variables at all. For example, Square might not declare any new instance variables of its own.

 

一个类不必声明实例变量。如果它到底还是需要任意实例变量,它可以简单地定义新方法并且依赖于它继承的实例变量。例如,Square可能不声明它自己的任意新的实例变量。

 

Inheriting Methods

 

继承方法

 

An object has access not only to the methods defined for its class but also to methods defined for its superclass, and for its superclass’s superclass, all the way back to the root of the hierarchy. For instance, a Square object can use methods defined in the Rectangle, Shape, Graphic, and NSObject classes as well as methods defined in its own class.

 

一个对象拥有不只有为它的类而定义的方法的访问权,还有为它的超类和它的超类的超类而定义的方法的访问权,一直向上到等级的根。例如,一个Square对象可以使用在Rectangle,Shape,Graphic,和NSObject中定义的方法,以及在它自己的类中定义的方法。

 

Any new class you define in your program can therefore make use of the code written for all the classes above it in the hierarchy. This type of inheritance is a major benefit of object-oriented programming. When you use one of the object-oriented frameworks provided by Cocoa, your programs can take advantage of the basic functionality coded into the framework classes. You have to add only the code that customizes the standard functionality to your application.

 

因此你在你的程序中定义的任何新类可以使用为等级中在它上面的所有类而编写的代码。此类继承是面向对象编程的一个主要好处。当你使用Cocoa提供的其中一个面向对象框架时,你的程序可以利用被编码进框架类中的基本功能。你只须添加定制了标准功能的代码到你的应用程序。

 

Class objects also inherit from the classes above them in the hierarchy. But because they don’t have instance variables (only instances do), they inherit only methods.

 

类对象还继承自等级中在它们上面的类。但因为它们没有实例变量(只有实例才有),所以它们只继承方法。

 

Overriding One Method with Another

 

用另一个方法覆盖一个方法

 

There’s one useful exception to inheritance: When you define a new class, you can implement a new method with the same name as one defined in a class farther up the hierarchy. The new method overrides the original; instances of the new class perform it rather than the original, and subclasses of the new class inherit it rather than the original.

 

对于继承有一个有用的例外:当你定义一个新类时,你可以用与等级中更高的一个类中定义的方法相同的名称来实现一个新方法。新的方法覆盖原来的方法;新类的实例执行它而非原来的方法,而新类的子类继承它而非原来的方法。

 

For example, Graphic defines a display method that Rectangle overrides by defining its own version of display. The Graphic method is available to all kinds of objects that inherit from the Graphic class—but not to Rectangle objects, which instead perform the Rectangle version of display.

 

例如,Graphic定义一个display方法,Rectangle通过定义它自己版本的display来覆盖它。Graphic的方法对于继承自Graphic类的所有类型对象是可用的——但对于Rectangle的对象则不然,它改为执行Rectangle版本的display。

 

Although overriding a method blocks the original version from being inherited, other methods defined in the new class can skip over the redefined method and find the original (see “Messages to self and super” to learn how).

 

虽然覆盖一个方法阻碍原来版本被重载,然而定义在新类中的其它方法可以略过被重新定义的方法而找到原来的(见“传给self和super的消息”以学习如何做到)。

 

A redefined method can also incorporate the very method it overrides. When it does, the new method serves only to refine or modify the method it overrides, rather than replace it outright. When several classes in the hierarchy define the same method, but each new version incorporates the version it overrides, the implementation of the method is effectively spread over all the classes.

 

一个被重新定义的方法还可以合并它所覆盖的那个方法。当它这样做时,新方法只担当简化或修改它覆盖的方法,而非彻底地取代它。然而当在等级中几个类定义相同的方法时,每个新版本合并它覆盖的版本,方法的实现有效地遍布所有类。

 

Although a subclass can override inherited methods, it can’t override inherited instance variables. Because an object has memory allocated for every instance variable it inherits, you can’t override an inherited variable by declaring a new one with the same name. If you try, the compiler will complain.

 

虽然一个子类可以覆盖被继承的方法,然而它不能覆盖被继承的实例变量。因为一个对象拥有为它继承的每个实例变量而分配的内存,你无法通过用相同的名称定义一个新变量来覆盖一个被继承的变量。如果你尝试这样做,编译器将报错。

 

Abstract Classes

 

抽象类

 

Some classes are designed only or primarily so that other classes can inherit from them. These abstract classes group methods and instance variables that can be used by a number of subclasses into a common definition. The abstract class is typically incomplete by itself, but contains useful code that reduces the implementation burden of its subclasses. (Because abstract classes must have subclasses to be useful, they’re sometimes also called abstract superclasses.)

 

一些类只是或主要被设计成其它类可以继承自它。这些抽象类分组方法和实例变量,它们可以被一些子类使用称为一个通用的定义。抽象类自身通常是不完整的,但包含有用的代码,它们降低它的子类的实现负担。(因为抽象类必须拥有子类以变得有用,所以它们有时也被称为抽象超类。)

 

Unlike some other languages, Objective-C does not have syntax to mark classes as abstract, nor does it prevent you from creating an instance of an abstract class.

 

不像其它一些语言那样,Objective-C没有语法来标注类为抽象的,也不阻止你创建一个抽象类的一个实例。

 

The NSObject class is the canonical example of an abstract class in Cocoa. You never use instances of the NSObject class in an application—it wouldn’t be good for anything; it would be a generic object with the ability to do nothing in particular.

 

NSObject类是在Cocoa中抽象类的典范示例。你从不在一个应用程序中使用NSObject类的实例——它用于任何东西都不好,它将是一个空泛对象,特别地它拥有什么都不做的能力。

 

The NSView class, on the other hand, provides an example of an abstract class, instances of which you might occasionally use directly.

 

另一方面,NSView类提供一个抽象类的一个示例,你可能有时直接使用它的实例。

 

Abstract classes often contain code that helps define the structure of an application. When you create subclasses of these classes, instances of your new classes fit effortlessly into the application structure and work automatically with other objects.

 

抽象类常常包含代码,它们有助于定义一个应用程序的结构。当你创建这些类的子类时,你的新类的实例轻易地适应应用程序的结构并且自动地处理其它对象。

 

Class Types

 

类类型

 

A class definition is a specification for a kind of object. The class, in effect, defines a data type. The type is based not just on the data structure the class defines (instance variables), but also on the behavior included in the definition (methods).

 

一个类定义是一类对象的规范。类事实上定义一种数据类型。类型不只是基于类定义的数据结构(实例变量),还基于在定义中包含的行为(方法)。

 

A class name can appear in source code wherever a type specifier is permitted in C—for example, as an argument to the sizeof operator:

 

一个类名可以出现在源码中,只要在那里一个类型指定器在C中是允许的——例如,作为给sizeof操作符的一个参数。

 

--------------------------------------------

 

int i = sizeof(Rectangle);

 

--------------------------------------------

 

Static Typing

 

静态类型化

 

You can use a class name in place of id to designate an object’s type:

 

你可以使用一个类名取代id的位置以指示一个对象的类型:

 

--------------------------------------------

 

Rectangle *myRectangle;

 

--------------------------------------------

 

Because this way of declaring an object type gives the compiler information about the kind of object it is, it’s known as static typing. Just as id is actually a pointer, objects are statically typed as pointers to a class. Objects are always typed by a pointer. Static typing makes the pointer explicit; id hides it.

 

因为声明一个对象类型的这种方式给予编译器关于它是什么类型对象的信息,所以它被称为静态类型化(注:即所谓的编译期类型检查)。正如id实际上是一个指针那样,对象被静态类型化作为指向一个类的指针。对象总是通过一个指针被类型化。静态类型化使得指针是显式的;id隐藏了它(注:id不需要出现*号)。

 

Static typing permits the compiler to do some type checking—for example, to warn if an object could receive a message that it appears not to be able to respond to—and to loosen some restrictions that apply to objects generically typed id. In addition, it can make your intentions clearer to others who read your source code. However, it doesn’t defeat dynamic binding or alter the dynamic determination of a receiver’s class at runtime.

 

静态类型化允许编译器做一些类型检查——例如,警告如果一个对象可以接收一个它看起来不能响应的消息——以及放宽一些应用到被空泛地类型化为id的对象的限制。另外,它可以让你的意图对于其它阅读你的源代码的人来说更清晰。然而,它不能击败动态绑定或在运行时改变一个接收者的类的动态确定。

 

An object can be statically typed to its own class or to any class that it inherits from. For example, because inheritance makes a Rectangle object a kind of Graphic object (as shown in the example hierarchy in Figure 1-1), a Rectangle instance can be statically typed to the Graphic class:

 

一个对象可以被静态类型化为它自己的类或被静态类型化为它继承自的任意类。例如,因为继承使一个Rectangle对象成为一种Graphic对象(正如在图1-1中示例层级中所示),所以一个Rectangle实例可以被静态类型化为Graphic类。

 

--------------------------------------------

 

Graphic *myRectangle;

 

--------------------------------------------

 

Static typing to the superclass is possible here because a Rectangle object is a Graphic object. In addition, it’s more than that because it also has the instance variables and method capabilities of Shape and Rectangle objects, but it’s a Graphic object nonetheless. For purposes of type checking, given the declaration described here, the compiler considers myRectangle to be of type Graphic. At runtime, however, if the myRectangle object is allocated and initialized as an instance of Rectangle, it is treated as one.

 

在这里静态类型化成超类是可能的,因为一个Rectangle类是一个Graphic类。另外,它不只是那样因为它还拥有Shape和Rectangle对象的实例变量和方法功能,尽管如此但它仍旧是一个Graphic对象。为了类型检查的目的,假设在这里所描述的声明,那么编译器认为myRectangle的类型是Graphic。然而,在运行时,如果myRectangle对象被分配并且初始化作为Rectangle的一个实例,它被视为是Rectangle实例。

 

See “Enabling Static Behavior” for more on static typing and its benefits.

 

参考“使能静态行为”以获得关于静态类型化和它的好处的更多内容。

 

Type Introspection

 

类型自省

 

Instances can reveal their types at runtime. The isMemberOfClass: method, defined in the NSObject class, checks whether the receiver is an instance of a particular class:

 

实例可以在运行时暴露它们的类型。定义在NSObject类中的isMemberOfClass:方法,检查接收者是否是一个特定类的一个实例:

 

--------------------------------------------

 

if ( [anObject isMemberOfClass:someClass] )

    ...

 

--------------------------------------------

 

The isKindOfClass: method, also defined in the NSObject class, checks more generally whether the receiver inherits from or is a member of a particular class (whether it has the class in its inheritance path):

 

还有定义在NSObject类中的isKindOfClass:方法,更一般地检查接收者是否继承自一个特定类或是一个特定类的一个成员(它在它的继承路径中是否拥有该类);

 

--------------------------------------------

 

if ( [anObject isKindOfClass:someClass] )

    ...

 

--------------------------------------------

 

The set of classes for which isKindOfClass: returns YES is the same set to which the receiver can be statically typed.

 

isKindOfClass:返回YES的类集合是和接收者可以被静态类型化成为的类集合是相同的集合。

 

Introspection isn’t limited to type information. Later sections of this chapter discuss methods that return the class object, report whether an object can respond to a message, and reveal other information.

 

自省不限于类型信息。本章后面的章节讨论返回类对象的方法,报告一个对象是否可以响应一个消息,以及暴露其它信息。

 

See NSObject Class Reference for more on isKindOfClass:, isMemberOfClass:, and related methods.

 

参考NSObject类参考文档以获得关于isKindOfClass:,isMemberOfClass:和相关方法的更多内容。

 

Class Objects

 

类对象

 

A class definition contains various kinds of information, much of it about instances of the class:

 

一个类定义包含各种类型的信息,其中大多数关于类的实例:

 

* The name of the class and its superclass

 

* 类与它的超类的名称

 

* A template describing a set of instance variables

 

* 一个描述一组实例变量的模板

 

* The declarations of method names and their return and parameter types

 

* 方法名称和它们返回与参数类型的描述

 

* The method implementations

 

* 方法的实现

 

This information is compiled and recorded in data structures made available to the runtime system. The compiler creates just one object, a class object, to represent the class. The class object has access to all the information about the class, which means mainly information about what instances of the class are like. It’s able to produce new instances according to the plan put forward in the class definition.

 

这些信息被编译并记录在对于运行时系统可用的数据结构中。编译器只创建一个对象,一个类对象,以代表该类。类对象拥有关于该类的所有信息的访问权,它意味着关于该类的实例像什么的大体信息。它能够根据在类定义中提出的计划生成新的实例。

 

Although a class object keeps the prototype of a class instance, it’s not an instance itself. It has no instance variables of its own and it can’t perform methods intended for instances of the class. However, a class definition can include methods intended specifically for the class object—class methods as opposed to instance methods. A class object inherits class methods from the classes above it in the hierarchy, just as instances inherit instance methods.

 

虽然一个类对象保存一个类实例的原型,但是它不是一个实例自身。它自身不拥有实例变量,而且它不能执行打算用于类实例的方法。然而,一个类定义可以包含特定地打算提供给类对象的方法——类方法相对于实例方法。一个类对象从等级中在它上方的类中继承类方法,正如实例继承实例方法那样。

 

In source code, the class object is represented by the class name. In the following example, the Rectangle class returns the class version number using a method inherited from the NSObject class:

 

在源代码中,类对象由类名来表示。在以下示例中,Rectangle类使用继承自NSObject类的一个方法来返回类版本号。

 

--------------------------------------------

 

int versionNumber = [Rectangle version];

 

--------------------------------------------

 

However, the class name stands for the class object only as the receiver in a message expression. Elsewhere, you need to ask an instance or the class to return the class id. Both respond to a class message:

 

然而,类名代表类对象仅当它是一个消息表达式中的接收者。在别的地方,你需要询问一个实例或类以返回类id。它们都响应一个class消息:

 

--------------------------------------------

 

id aClass = [anObject class];

id rectClass = [Rectangle class];

 

--------------------------------------------

 

As these examples show, class objects can, like all other objects, be typed id. But class objects can also be more specifically typed to the Class data type:

 

正如这些示例所示,类对象可以像其它所有对象那样被类型化为id。但类对象还可以被更特定地类型化为Class数据类型:

 

--------------------------------------------

 

Class aClass = [anObject class];

Class rectClass = [Rectangle class];

 

--------------------------------------------

 

All class objects are of type Class. Using this type name for a class is equivalent to using the class name to statically type an instance.

 

所有类对象属于类型Class。对一个类使用此类型的名称等效于使用类名来静态类型化一个实例。

 

Class objects are thus full-fledged objects that can be dynamically typed, receive messages, and inherit methods from other classes. They’re special only in that they’re created by the compiler, lack data structures (instance variables) of their own other than those built from the class definition, and are the agents for producing instances at runtime.

 

因此类对象是成熟的对象,可以被动态类型化,接收消息,并且从其它类中继承方法。它们只是特殊在它们是被编译器创建,缺乏它们自己的数据结构(实例变量)而非从类定义中构建,并且是用于在运行期生成实例的代理。

 

--------------------------------------------

 

Note: The compiler also builds a metaclass object for each class. It describes the class object just as the class object describes instances of the class. But while you can send messages to instances and to the class object, the metaclass object is used only internally by the runtime system.

 

注意:编译器还为每个类构建一个元类对象,它描述类对象正如类对象描述类的实例那样。不过当你可以发送消息到实例和到类对象时,元类对象只是内部地被运行时系统使用。

 

--------------------------------------------

 

Creating Instances

 

创建实例

 

A principal function of a class object is to create new instances. This code tells the Rectangle class to create a new rectangle instance and assign it to the myRectangle variable:

 

一个类对象的主要功能是创建新实例。这段代码叫Rectangle类创建一个新的矩形实例并把它赋到myRectangle变量:

 

--------------------------------------------

 

id  myRectangle;

myRectangle = [Rectangle alloc];

 

--------------------------------------------

 

The alloc method dynamically allocates memory for the new object’s instance variables and initializes them all to 0—all, that is, except the isa variable that connects the new instance to its class. For an object to be useful, it generally needs to be more completely initialized. That’s the function of an init method. Initialization typically follows immediately after allocation:

 

alloc方法为新对象的实例变量动态地分配内存并全部初始化它们为0——就是说,所有实例变量除了连接新实例到它的类的isa变量。对于一个将是有用的对象,它通常需要更完整地初始化。那是init方法的功能。初始化典型地立即跟在分配的后面:

 

--------------------------------------------

 

myRectangle = [[Rectangle alloc] init];

 

--------------------------------------------

 

This line of code, or one like it, would be necessary before myRectangle could receive any of the messages that were illustrated in previous examples in this chapter. The alloc method returns a new instance and that instance performs an init method to set its initial state. Every class object has at least one method (like alloc) that enables it to produce new objects, and every instance has at least one method (like init) that prepares it for use. Initialization methods often take parameters to allow particular values to be passed and have keywords to label the parameters (initWithPosition:size:, for example, is a method that might initialize a new Rectangle instance), but every initialization method begins with “init”.

 

在myRectangle可以接收到在本章中前面示例里描述的任意消息之前,这行代码,或好像它的代码,是必需的。alloc方法返回一个新的实例,而那个实例执行一个init方法以设置它的最初状态。每个类对象拥有至少一个使它能够生成新对象的方法(像alloc),并且每个实例至少有一个准备它以供使用的方法(像init)。初始化方法常常传入参数以允许特殊值被传入和拥有关键词以标签化参数(例如,initWithPosition:size:是一个方法,它可能是一个初始化一个新的Rectangle实例的方法),但每个初始化方法以“init”开头。

 

Customization with Class Objects

 

使用类对象的自定义

 

It’s not just a whim of the Objective-C language that classes are treated as objects. It’s a choice that has intended, and sometimes surprising, benefits for design. It’s possible, for example, to customize an object with a class, where the class belongs to an open-ended set. In AppKit, for example, an NSMatrix object can be customized with a particular kind of NSCell object.

 

类被视为对象不只是Objective-C语言的一个怪念头。它是一个已经有意的选择,以及有时令人惊讶的,对设计的好处。例如,可以用一个类自定义一个对象,在那里类属于一个开放式(注:无限制)的集合。例如,在AppKit中,NSMatrix对象可以用一个特殊类型的NSCell对象自定义。

 

An NSMatrix object can take responsibility for creating the individual objects that represent its cells. It can do this when the matrix is first initialized and later when new cells are needed. The visible matrix that an NSMatrix object draws on the screen can grow and shrink at runtime, perhaps in response to user actions. When it grows, the matrix needs to be able to produce new objects to fill the new slots that are added.

 

一个NSMatrix对象可以负责创建代表它的单元格的单独对象。它可以做这件事当矩阵首次被初始化并且稍后当需要新的单元格时。一个NSMatrix对象绘画在屏幕上的可见矩阵可以在运行时增长和收缩,可能用于响应用户动作。当它增长时,矩阵需要能够生成新对象以填充被添加的新槽。

 

But what kind of objects should they be? Each matrix displays just one kind of NSCell, but there are many different kinds. The inheritance hierarchy in Figure 1-3 shows some of those provided by AppKit. All inherit from the generic NSCell class.

 

但它们应该是什么类型的对象?每个矩阵只显示一种类型的NSCell,但有许多不同类型的NSCell。在图1-3中继承等级展示AppKit提供的那些类型。所有继承自一般的NSCell类。

 

--------------------------------------------

 

Figure 1-3  The inheritance hierarchy for NSCell

 

图1-3 NSCell的继承等级

 

(图略:

NSObject -> NSCell -> NSBrowserCell

                   -> NSActionCell -> NSButtonCell -> NSMenuCell

                                   -> NSTextFieldCell

                                   -> NSSliderCell

                                   -> NSFormCell

 

--------------------------------------------

 

When a matrix creates NSCell objects, should they be NSButtonCell objects to display a bank of buttons or switches, NSTextFieldCell objects to display fields where the user can enter and edit text, or some other kind of NSCell? The NSMatrix object must allow for any kind of cell, even types that haven’t been invented yet.

 

当一个矩阵创建NSCell对象时,它们应该是NSButtonCell对象以显示一堆按钮或开关,是NSTextFieldCell对象以显示用户可以输入和编辑文本的域,还是一些其它类型的NSCell?NSMatrix对象必须允许所有类型的单元格,甚至是还未被发明的类型。

 

One solution to this problem would be to define the NSMatrix class as abstract and require everyone who uses it to declare a subclass and implement the methods that produce new cells. Because they would be implementing the methods, users could make certain that the objects they created were of the right type.

 

这个问题的一个解决方案是定义NSMatrix作为抽象的并且需要使用它的每个人声明一个子类并且实现生成新单元格的方法。因为它们正要继承该方法,所以用户可以确定它们创建的对象是属于正确的类型。

 

But this solution would require users of the NSMatrix class to do work that ought to be done in the NSMatrix class itself, and it unnecessarily proliferates the number of classes. Because an application might need more than one kind of matrix, each with a different kind of cell, it could become cluttered with NSMatrix subclasses. Every time you invented a new kind of NSCell, you’d also have to define a new kind of NSMatrix. Moreover, programmers on different projects would be writing virtually identical code to do the same job, all to make up for the failure of NSMatrix to do it.

 

但这种解决方案将需要NSMatrix类的用户做应该在NSMatrix类自身里完成的工作,而且它不必要地增加了类的数量。因为一个应用程序可能需要多于一种类型的矩阵,每个带有不同类型的单元格,所以使用NSMatrix子类可以会变得混乱。每次你发明一种新类型的NSCell,你还不得不定义一种新类型的NSMatrix。此外,事实上在不同项目上的程序员将编写同样的代码来做相同的工作,所有这些都是因为NSMatrix不能做的而补偿。

 

A better solution, and the solution the NSMatrix class adopts, is to allow NSMatrix instances to be initialized with a kind of NSCell—that is, with a class object. The NSMatrix class also defines a setCellClass: method that passes the class object for the kind of NSCell object an NSMatrix should use to fill empty slots:

 

一个较好的解决方案,而且NSMatrix类采纳的方案,是允许NSMatrix使用一种类型的NSCell来初始化——就是说,使用类对象。NSMatrix类还定义一个setCellClass:方法,它传递NSCell对象的类型的类对象,一个NSMatrix应该使用它来填充空槽:

 

--------------------------------------------

 

[myMatrix setCellClass:[NSButtonCell class]];

 

--------------------------------------------

 

The NSMatrix object uses the class object to produce new cells when it’s first initialized and whenever it’s resized to contain more cells. This kind of customization would be difficult if classes weren’t objects that could be passed in messages and assigned to variables.

 

NSMatrix对象使用类对象以生成新的单元格,当它首次被初始化以及无论何时它被改变大小以包含更多单元格时。这种类型的自定义将是困难的,如果类不是可以在消息中传递并且赋给变量的对象。

 

Variables and Class Objects

 

变量和类对象

 

When you define a new class, you can specify instance variables. Every instance of the class can maintain its own copy of the variables you declare—each object controls its own data. There is, however, no class variable counterpart to an instance variable. Only internal data structures, initialized from the class definition, are provided for the class. Moreover, a class object has no access to the instance variables of any instances; it can’t initialize, read, or alter them.

 

当你定义一个新类时,你可以指定实例变量。该类的每个实例可以维护你所声明变量的它自己的复制——每个对象控制它自己的数据。然而,没有对应于一个实例变量的类变量副本。只有初始化自类定义的内部数据结构,被提供用于该类。而且,类对象没有对任意实例的实例变量的访问权;它无法初始化、读取、或者改变它们。

 

For all the instances of a class to share data, you must define an external variable of some sort. The simplest way to do this is to declare a variable in the class implementation file:

 

对于要共享数据的一个类的所有实例,你必须定义一些种类的一个外部变量。做这件事最简单的方法是在类实现文件中声明一个变量:

 

--------------------------------------------

 

int MCLSGlobalVariable;

 

@implementation MyClass

// implementation continues

// 实现继续

 

--------------------------------------------

 

In a more sophisticated implementation, you can declare a variable to be static, and provide class methods to manage it. Declaring a variable static limits its scope to just the class—and to just the part of the class that’s implemented in the file. (Thus unlike instance variables, static variables cannot be inherited by, or directly manipulated by, subclasses.) This pattern is commonly used to define shared instances of a class (such as singletons; see “Creating a Singleton Instance” in Cocoa Fundamentals Guide).

 

在一个更复杂的实现里,你可以声明一个变量为静态,并且提供类名以管理它。声明一个变量为静态限制它的作用域只用于该类——并且只用于在该文件中实现的类的部分。(不像实例变量那样,静态变量不能被子类继承,或者直接地被子类操纵。)这种模式通常被用于定义一个类的共享实例(诸如单实例;参见在Cocoa基础指南中的“创建一个单实例”)。

 

--------------------------------------------

 

static MyClass *MCLSSharedInstance;

 

@implementation MyClass

 

+ (MyClass *)sharedInstance

{

    // check for existence of shared instance

    // create if necessary

    return MCLSSharedInstance;

    // 检查共享实例的存在

    // 在需要时创建

}

// implementation continues

// 实现继续

 

--------------------------------------------

 

Static variables help give the class object more functionality than just that of a factory producing instances; it can approach being a complete and versatile object in its own right. A class object can be used to coordinate the instances it creates, dispense instances from lists of objects already created, or manage other processes essential to the application. In the case when you need only one object of a particular class, you can put all the object’s state into static variables and use only class methods. This saves the step of allocating and initializing an instance.

 

静态变量有助于给予类对象更多功能而非只是一个工厂产生实例;它可以靠自身能力接近于一个完整和通用的对象。一个类对象可以被用于协调它创建的实例,从已经创建的对象列表中分配实例,或者管理其它对于应用程序来说是本质的处理。在当你只需要一个特定类的一个对象的情况下,你可以放置所有对象的状态进静态变量并且只使用类方法。它保存分配和初始化一个实例的步骤。

 

--------------------------------------------

 

Note: It is also possible to use external variables that are not declared static, but the limited scope of static variables better serves the purpose of encapsulating data into separate objects.

 

注意:也可以使用不声明为静态的外部变量,但静态变量的有限作用域更好地管用在封装数据进单独的对象中。

 

--------------------------------------------

 

Initializing a Class Object

 

初始化一个类对象

 

If you want to use a class object for anything besides allocating instances, you may need to initialize it just as you would an instance. Although programs don’t allocate class objects, Objective-C does provide a way for programs to initialize them.

 

如果你想使用一个类对象用于除分配实例外的任意事情,你可能需要初始化它正如你初始化一个实例那样。虽然程序不分配类对象,然而Objective-C提供一种方式给程序初始化它。

 

If a class makes use of static or global variables, the initialize method is a good place to set their initial values. For example, if a class maintains an array of instances, the initialize method could set up the array and even allocate one or two default instances to have them ready.

 

如果一个类使用静态或全局变量时,初始化方法是设置它们的初始化值的好地方。例如,如果一个类维护实例的一个数组,那么初始化方法可以配置数组,甚至分配一个或两个默认实例以让它们准备好。

 

The runtime system sends an initialize message to every class object before the class receives any other messages and after its superclass has received the initialize message. This sequence gives the class a chance to set up its runtime environment before it’s used. If no initialization is required, you don’t need to write an initialize method to respond to the message.

 

运行时系统发送一个初始化消息到每个类对象,在类接收其它任意消息之前和在它超类已经接收了初始化消息之后。这个序列给予该类一个机会在它被使用前配置它的运行时环境。如果没有初始化是必需的,那么你不需要编写一个初始化方法以响应该消息。

 

Because of inheritance, an initialize message sent to a class that doesn’t implement the initialize method is forwarded to the superclass, even though the superclass has already received the initialize message. For example, assume class A implements the initialize method, and class B inherits from class A but does not implement the initialize method. Just before class B is to receive its first message, the runtime system sends initialize to it. But, because class B doesn’t implement initialize, class A’s initialize is executed instead. Therefore, class A should ensure that its initialization logic is performed only once, and for the appropriate class.

 

因为继承,所以发送给一个没有实现初始化方法的类的初始化消息被定向至超类,即便超类已经接收初始化消息。例如,假设类A实现初始化方法,而类B继承自类A但没有实现初始化方法,正好在类B打算接收它的第一个消息之前,运行时系统发送初始化给它。但是,因为类B不实现初始化,所以改为执行类A的初始化。因此,类A应该确保它的初始化逻辑被执行仅一次,并且用于合适的类。

 

To avoid performing initialization logic more than once, use the template in Listing 1-1 when implementing the initialize method.

 

为了避免执行初始化逻辑多于一次,当实现初始化方法时请使用列表1-1中的模板。

 

Listing 1-1  Implementation of the initialize method

 

列表1-1 初始化方法的实现

 

--------------------------------------------

 

+ (void)initialize

{

  if (self == [ThisClass class]) {

        // Perform initialization here.

        // 在这里执行初始化

        ...

    }

}

 

--------------------------------------------

 

--------------------------------------------

 

Note: Remember that the runtime system sends initialize to each class individually. Therefore, in a class’s implementation of the initialize method, you must not send the initialize message to its superclass.

 

注意:记住运行时系统单独地发送初始化给每个类。因此,在一个类的初始化方法实现中,你不必发送初始化消息给它的超类。

 

--------------------------------------------

 

Methods of the Root Class

 

根类的方法

 

All objects, classes and instances alike, need an interface to the runtime system. Both class objects and instances should be able to introspect about their abilities and to report their place in the inheritance hierarchy. It’s the province of the NSObject class to provide this interface.

 

和所有对象,类和实例相似,需要一个接口给运行时系统。类对象和实例都应该能够自省有关它们的能力以及报告它们在继承等级中的位置。这是NSObject类提供此接口的职责。

 

So that NSObject methods don’t have to be implemented twice—once to provide a runtime interface for instances and again to duplicate that interface for class objects—class objects are given special dispensation to perform instance methods defined in the root class. When a class object receives a message that it can’t respond to with a class method, the runtime system determines whether there’s a root instance method that can respond. The only instance methods that a class object can perform are those defined in the root class, and only if there’s no class method that can do the job.

 

因此NSObject方法不必被实现两次——一次用来提供一个运行时接口给实例,而再次用来复制用于类对象的接口——类对象被给予特殊许可执行定义在根类中的实例方法。当一个类对象接收一个消息,而它不能用一个类方法响应,那么运行时系统确定是否有一个可以响应的根实例方法。一个类对象可以执行的唯一实例方法是那些定义在根类中的实例方法,而且只是如果没有可以做该工作的类方法。

 

For more on this peculiar ability of class objects to perform root instance methods, see NSObject Class Reference.

 

想获得关于类对象执行根实例方法的这种特有能力的更多内容,参考NSObject类参考文档。

 

Class Names in Source Code

 

源代码中的类名

 

In source code, class names can be used in only two very different contexts. These contexts reflect the dual role of a class as a data type and as an object:

 

在源码中,类名只可以用于两个非常不同的上下文中。这些上下文反映一个类的双重角色作为一个数据类型和作为一个对象:

 

* The class name can be used as a type name for a kind of object. For example:

 

* 类名可以被用作一个类型名称对应一类对象。例如:

 

--------------------------------------------

 

Rectangle *anObject;

 

--------------------------------------------

 

Here anObject is statically typed to be a pointer to a Rectangle object. The compiler expects it to have the data structure of a Rectangle instance and to have the instance methods defined and inherited by the Rectangle class. Static typing enables the compiler to do better type checking and makes source code more self-documenting. See “Enabling Static Behavior” for details.

 

这里anObject比静态类型化为指向一个Rectangle对象的一个指针。编译器期待它拥有一个Rectangle实例的数据结构并且拥有Rectangle类定义和继承的实例方法。静态类型化使编译器能执行更好的类型检查以及让源代码更加自文档化。参见“使能静态行为”以获得细节。

 

Only instances can be statically typed; class objects can’t be, because they aren’t members of a class, but rather belong to the Class data type.

 

只有实例可以被静态类型化;类对象不可以,因为它们不是一个类的成员,相反属于Class数据类型。

 

* As the receiver in a message expression, the class name refers to the class object. This usage was illustrated in several of the earlier examples. The class name can stand for the class object only as a message receiver. In any other context, you must ask the class object to reveal its id (by sending it a class message). This example passes the Rectangle class as a parameter in an isKindOfClass: message:

 

* 作为一个消息表达式中的接收者,类名倾向于作为类对象。这种用法被描述在前面的几个例子中。类名可以代表类对象仅作为一个消息接收者。在其它任意上下文中,你必须询问类对象以暴露它的id(通过发送它一个class消息)。这个示例传进Rectangle class作为一个isKindOfClass:消息中的一个参数:

 

--------------------------------------------

 

if ( [anObject isKindOfClass:[Rectangle class]] )

    ...

 

--------------------------------------------

 

It would have been illegal to simply use the name “Rectangle” as the parameter. The class name can only be a receiver.

 

简单地使用名称“Rectangle”作为参数将是非法的。类名可以只是一个接收者。

 

If you don’t know the class name at compile time but have it as a string at runtime, you can use NSClassFromString to return the class object:

 

如果你在编译期不知道类名但在运行时拥有它作为一个字符串,你可以使用NSClassFromString以返回类对象:

 

--------------------------------------------

 

NSString *className;

    ...

if ( [anObject isKindOfClass:NSClassFromString(className)] )

    ...

 

--------------------------------------------

 

This function returns nil if the string it’s passed is not a valid class name.

 

这个函数返回nil如果它被传入的字符串不是一个有效的类名。

 

Class names exist in the same namespace as global variables and function names. A class and a global variable can’t have the same name. Class names are the only names with global visibility in Objective-C.

 

类名存在于相同的名字空间作为全剧变量和函数名称。一个类和一个全局变量不能拥有相同的名称。类名是在Objective-C中带有全局可见性的唯一名称。

 

Testing Class Equality

 

测试类的相等性

 

You can test two class objects for equality using a direct pointer comparison. It is important, though, to get the correct class. There are several features in the Cocoa frameworks that dynamically and transparently subclass existing classes to extend their functionality (for example, key-value observing and Core Data do this—see Key-Value Observing Programming Guide and Core Data Programming Guide respectively). In a dynamically-created subclass, the class method is typically overridden such that the subclass masquerades as the class it replaces. When testing for class equality, you should therefore compare the values returned by the class method rather than those returned by lower-level functions. Put in terms of API, the following inequalities pertain for dynamic subclasses:

 

你可以使用一个直接指针比较来测试两个类对象的相等性。虽然,重要的是获得正确的类。在Cocoa框架中有几个特性,动态地和透明地子类化现存类以扩展它们的功能(例如,键-值观察和核心数据做这种事情——请分别参考键-值观察编程指南和核心数据编程指南)(注:key-value observing简称KVO,提供一种机制允许对象被通知其它对象的指定属性的改变。而Core Data框架,对与对象生命周期相关和对象图管理的通用任务,包括持久化,提供通用和自动化的解决方案)。在一个被动态创建的子类中,类方法通常被覆盖以使子类假装成它所取代的类。因此当测试类的相等性时,你应该比较class方法返回的值而非较低层次函数返回的值。从API的角度看,以下不等式适合于动态子类:

 

--------------------------------------------

 

[object class] != object_getClass(object) != *((Class*)object)

 

--------------------------------------------

 

You should therefore test two classes for equality as follows:

 

因此你应该如下所示测试两个类的相等性:

 

--------------------------------------------

 

if ([objectA class] == [objectB class]) { //...

 

--------------------------------------------

 

--------------------------------------------

 

(c) 2011 Apple Inc. All Rights Reserved. (Last updated: 2011-10-12)

 

(c) 2011年Apple公司版权所有。(最后更新:2011-10-12)

 

(本人翻译欠佳,请以官方文档为准。或者参考:

* 基于Objective-C的面向对象编程(官方中文文档)

http://www.apple.com.cn/developer/mac/library/documentation/Cocoa/Conceptual/OOP_ObjC/Introduction/chapter_1_section_1.html


  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值