......翻译苹果官方文档--《The Objective-C Programming Language》
本章主要介绍Objective_C语言使用和实现对象,类,和消息的基本原理。也介绍一些Objective_C 的runtime
一.运行时系统
Objective_C可以把一些编译和链接时的一些行为决定推迟到运行时。比如,它可以动态的运行创建对象或者引用什么方法的操作。因此,这门语言不仅仅需要一个编译器,还需要一个运行时的系统来运行编译过的代码。这个运行时的系统就像是objective_C语言的操作系统一样,来使语言运行工作。然而,你不需要直接与runtime进行交互。可以通过文档《Objective-C Runtime Programming Guide 》来学习了解runtime提供的功能。
二.对象
正如它的名字,面向对象的编程是围绕对象来建立的。对象通过一个数据可以使用或者对其有影响的特定操作来关联该数据。Objective-C提供了一种数据类型来标识对象变量而不需要指定对象的特定类。
1.对象基本原理
对象将数据与其可以使用或影响该数据的特定操作关联起来。在Objective_C中,这些操作被称为对象的方法;它们影响的数据是它的实例变量(在其他环境中,可能被称为ivars或者成员变量)。本质上,对象是将一个数据结构(实例变量)和一组过程(方法)捆绑到一个独立的编程单元中。
在Objective_C中,一个对象的成员变量在该对象的内部。通常,只能通过对象的方法来访问该对象的状态。对象必须提供方法来使其他人来了解对象的一些信息。例如,矩形应该提供方法来展示它的size和position。
此外,一个对象只能访问它自己的方法而不能错误的运行其他对象的方法。就像一个 C函数通过在其他程序中隐藏它的局部变量来保护它们。一个对象也应该隐藏它的成员变量和方法实现。
2.id
在Objective_C中,可以通过id来标识各种不同的数据类型。id类型是一个通用的类型,它不仅可以标识类的成员变量,也可以标识类对象本身。
id anObject;
对于Objective_C面向对象的结构,比如方法的返回值,可以用id来代替int当作它默认的数据类型。
关键字nil 被定义为一个空对象,是一个值为0的id类型。id,nil,以及其他的一些Objective_C基本类型定义在头文件 objc/objc.h 的头文件中。
id定义为一个指向对象数据结构的指针:
typedef struct objc_object {
Class isa;
} *id;
每个对象都有一个isa的变量来指定它是哪个类的实例。因为Class类型本身被定义为一个指针:
typedef struct objc_class *Class;
ISA变量经常被称为“ISA指针”。
3.动态类型
id类型是完全的非限制性的。它本身,除了它是一个对象,它不包含其他的任何的关于对象的信息。在某种程度上,一个程序通常需要找到对象包含的特定信息。由于id类型设计的就是不能给编译器提供这些特定信息,因此每个对象必须可以在运行时提供这些信息。
isa这个成员变量标识对象的类----它是什么类型的对象。具有相同行为(方法)和相同类型的数据(实例变量)的对象是同一类的成员。
对象因此在运行时动态类型化。每当它需要,运行时系统只需要通过询问对象便可以准确的找到这个对象属于的类。(要了解更多关于运行时,参考Objective-C Runtime Programming Guide。)在Objective-C中动态类型是动态绑定的基础,稍后讨论。
ISA变量还允许对象运行introspection以了解自己(或其他对象)。编译器会记录关于类定义信息的数据结构,以供运行时系统使用。运行时系统的函数在运行时使用ISA来查找这些信息。通过运行时系统,你可以确定一个对象是否实现了一个特定的方法或确定它的父类的名称。
类是特定类型的对象,类名可以作为类型名称。
4.内存管理
在任何程序中,当一个对象不再使用的时候都需要将其销毁。也要确保仍在使用的对象不被销毁。
Objective-C提供三种内存管理方式:
Automatic Reference Counting(ARC)
Manual Reference Counting
Garbage collection
三.对象消息
1.消息语法
可以通过给对象发送消息来告诉对象做什么事情。消息表达式的语法为:
[receiver message]
接受者是一个对象,message告诉这个对象做什么。在源代码中,消息是方法的名称以及所需要的参数。当一个消息被发送,运行时系统从接受者的本领中选择适当的方法并引用它。
例如,这个消息告诉myRectangle对象执行它的display方法:
[myRectangle display];
由于消息的方法名称用于“选择”实现一个方法,所以消息中的方法名称通常被称为选择器。
一个选择器名称包括名称的所有部分,包括冒号。例如选择器setOriginX:Y:。因为它需要两个参数,所以它有两个冒号。选择器名称不包含其他任何类型,如返回类型或参数类型。
OC不支持可变(可选)参数。
原则上一个方法的第二个参数可以没有标签,比如:
[myRectangle setOrigin:30.0 :50.0];
当然,这种命名方法是不推荐的。
消息表达式可以嵌套另一个消息表达式:
[myRectangle setPrimaryColor:[otherRect primaryColor]];
Objective-C提供一种点操作来方便快捷的访问对象的方法和属性。
2.向空对象发送消息
在Objective-C中,允许向一个空对象发送消息---它在运行时是无效的。Cocoa中有几种模式是运用这个事实。发送到空对象的消息有时候是有用的:
a.如果一个方法返回一个对象,然后一个消息发送到空对象上,会返回0(nil)。例如:
Person *motherInLaw = [[aPerson spouse] mother];
比如:这里的spouse对象是空的话,mother会给空对象传递一个消息,结果返回为0(空)。
b.如果方法返回一个泛型指针(void *),消息发送到一个空对象的话,会返回0。
c.如果方法返回一个结构体,消息发送到nil的话会返回0。这个结构体的每个成员都是0。
d.如果方法的返回类型不是上述中的类型的话,发送到nil的消息的返回值是不确定的。
3.接收者的成员变量
方法可以自动访问接收者对象的成员变量。你不需要把它们当作参数传递给方法。方法可以获得接收者及它的成员变量,而不需要把它们声明为参数。
这个机制简化了Objective-C的源代码,而且支持对象和消息面向对象的编程思想。消息发送到接收者就类似于一封信邮寄到您家一样。消息的参数携带从外界传递给接收者的信息。
4.多态性
一个对象只能操作那些为它定义的方法。它不能调用为其他对象定义的方法,即使另一个对象和它有一个同名的方法。因此,两个对象可以对同一消息做出不同的响应。例如,接收到显示消息的每一种对象都可以以自己的方式显示自己。一个圆和一个矩形会对跟踪光标的相同指令做出不同的响应。
这个特征称为多态性。它在面向对象程序设计中起着重要的作用。连同动态绑定,它允许您编写可以适用于任意数量的不同类型的对象的代码,而不必在编写代码时选择它们属于什么类型的对象。他们甚至可以是程序员后来在其他项目上开发的对象。如果您在代码中将display消息发送到id类型的变量,任何具有display方法的对象都是一个潜在的接收器。
5.动态绑定
函数调用和消息之间的一个关键区别是函数和它的参数在编译后的代码中被连接在一起,而在程序运行和发送消息之前,消息和接收对象之间是不明确的。因此,调用消息的确切方法只能在运行时确定,而不是在编译代码时执行。
当一个消息被发送以后,一个运行时的消息机制会会寻找消息的接收者以及消息中的方法名字。它定位接收者中与名字匹配的方法的实现,然后调用方法,并把它当作指针传递给接收者的成员变量。
消息的动态绑定方法与多态性的结合使用,使面向对象编程更加灵活性强大。因为每个对象都有其自己版本的一个方法,一条Objective-C语句可以使其运行出不同的结果,不需要发送不同的消息,只通过改变接收消息的对象即可。
四.类