Objective-C 的对象模型
最近稍微学习了一点 Objective-C ,做笔记和做编码练习都是巩固学习的好方法。整理记录脑子里的新知识有助于理清思路,发现知识盲点以及错误的理解。
Objective-C 和 C++ 同样从兼容 C 语言开始,以给 C 语言增加面向对象为初衷,他们的出现的时间都很类似(1983 年左右)。但面向对象编程的源头却不同:C++ 受 Simula 和 Ada 的影响比较多,而 Objective-C 的相关思想源至 Smalltalk ,最终的结果是他们在对象模型上有不小的差异。
以我这些天粗浅的了解,Objective-C 似乎比 C++ 更强调类型的动态性,而牺牲了一些执行性能。不过这些牺牲,由于模型清晰,可以在今天,由更先进的编译技术来弥补了。
我对 C++ 的认知比 Objective-C 要多的多,所以对 C++ 开发中会遇到的问题的了解也多的多。在学习 Objective-C 的过程中,我发现很多地方都可以填上曾经在 C++ 开发中遇到的问题。当然,Objective-C 一定也有它自己的坑,只是我才刚开始,没有踩到过罢了。
ObjC 的类方法调用的形式,更接近于向对象发送消息。语法写作:
[obj message]
如果方法带有参数,那么就写作
[obj param:value]
方法和名称和参数的名称是一体的,参数决定了方法是什么。如果有多个参数,那么写作:
[obj param1:value1 param2:value2]
注意,如果一个类有两个方法,一个有一个参数,一个有两个参数。即使两个参数的版本中有一个参数名称和单个参数版本的相同,它们也是两个不同的方法。ObjC 不支持默认参数的语法。
C++ 调用对象的方法就更接近于 C 的函数调用。两相比较,可以发现 ObjC 的语法让代码可读性更强。你可以很容易的理解参数的用途,也不怕方法参数过多时,一串参数写漏或写错次序了。
和 C++ 一样,ObjC 的类声明和实现是分离的。但做的比 C++ 更彻底。ObjC 不能在声明的代码段中写 inline 函数。这看起来牺牲了一些运行性能,但当实现部分更好的分离。作为补充,ObjC 有 @property ,可以帮助程序员简化实现,也可以让编译器生成更好的代码。
声明一个类写成这样:
@interface class : baseclass { type a; } - (void) method; - (void) messge: (type) param; + (id) create ; @end
ObjC 利用了 C 语言中没有使用的符号 @ 来扩展 C 的语法,而不是用 C++ 里增加关键字的方式。这或许是一个对语言扩展更简单的做法,而不用考虑兼容性。C++ 就得精心挑选新增加的关键字,尽量回避那些已有代码中高频出现的单词。
类的数据段和方法是分离的。数据描述放在 {} 中,方法写在其后,在 @end 之前。
"-" 开头的方法是实例方法,也就是 C++ 中的成员方法。成员方法中可以通过 self 取到实例指针,也就是 C++ 中的 this 指针。
同样,ObjC 也支持类方法,也就是 C++ 中的 static 成员方法。通常是用来构造实例。声明方法是在方法名前写一个 + 号。
和 C++ 不同,ObjC 是有类对象的。类对象里有超类指针、类名、类方法列表指针,还有类对象的字节大小等元信息。而 C++ 中是用 RTTI 类实现不完全的类似功能的。
调用类方法和调用实例方法在语法上没有什么不同。类名就是类对象的名字。
ObjC 不支持多继承,没有私有、公开这些修饰符。
ObjC 的类方法实现必须写在同一个源文件里。不像 C++ 有 :: 操作符,ObjC 在实现方法时不写类的名字,而是把所有实现都写在 @implementation class ... @end 之间。访问基类,也可以方便的使用 super 关键字。
那么,如果一个类的方法太多,不适合写在同一个源文件中怎么办?
ObjC 提供了 category 这个概念。
可以通过 category 为一个类添加一些方法。category 和继承是不同的,不能为类添加新的成员变量,所以它不会改变类对象的内存布局。添加了方法的类还是原来那个类。
category 的语法是这样的:
@interface class (category) - newmethod; @end
这样,就给 class 类添加了一个方法 newmethod ,并归类在 category 下。
和 C++ 不同,ObjC 的方法更具动态性。你可以在运行时任意调用一个对象的方法,而不用管它是否存在。ObjC 支持 id 这个类型。 id 其实就是对象指针,任何类型的对象都可以被 id 引用,并可以方便的向其发送消息(方法调用)。如果方法不存在,会抛出运行时错误。
向一个指定类型发送一个不存在的消息,会得到一个编译期警告,而不是编译错误。当然,我们不能随便忽略编译期警告,如果我们清楚的知道运行期这个对象可以处理这个消息,那么可以给类加一个 category 但不必实现它。这样,编译器就能了解新的方法了。
利用 category 可以方便的一个庞大的类拆分成独立的模块。在 C++ 中,比较接近的概念是 friend ,不过 friend 不易被优雅的使用。
既然方法可以被运行期检查,那么方法本身在 ObjC 中也可以被当成一种类型来处理。比较接近的 C++ 中的概念是 成员方法指针。回顾学习 C++ 的经历就能回忆起当年使用 ::* 或是 ->* 的头痛经历。ObjC 中的方法可以运行期绑定, @selector(method:) 的语法也简单的多。
在 NSObject 中就提供了一个叫 respondsToSelector: 的方法,接受一个 selector 用来检查自己是否可以接受这个消息。
ObjC 也提供了类似 Java 的 interface 或是 C++ 的纯虚类的东西,在 ObjC 中被称为 @protocol 。
@protocol 可以看成是一种没有数据成员的虚类。一个实际的类可以声明自己实现了某些协议,语法是
@interface class : base <protocol> { // variables } // methods @end
和继承不同,一个类可以声明多个协议。然后在 @implementation 中必须一一实现它们。
如上所述,ObjC 已经做到了运行期的方法绑定,所以 @protocol 只是做了更严格的编译检查。在新版的 ObjC 2.0 中,追加了 @optional 和 @required 用来描述那些方法的实现是可选的,哪些必须实现。
ObjC 的基础库比 C++ 更完整,标准化要好的多,也和语言结合的更紧密。
比如 NSString 是一个基础类,用于处理字符串。同时,语言也提供 @"string" 的语法方便的生成 NSString 对象。
ObjC 保留了 C 中的 printf 式的字符串操作形式,对比 C++ 重载移位操作符的形式,我想要更清爽一些。
对于 ObjC 对象,使用 %@ 来表示。给对象增加 description 方法就可以让处理函数知道该如何处理这个对象的 %@ 行为。
Comments
Posted by: xiaohuang | (34) August 28, 2016 10:04 AM
Posted by: headchen | (33) February 24, 2016 04:10 PM
Posted by: headchen | (32) February 24, 2016 02:09 PM
Posted by: 胡力友 | (31) March 7, 2015 10:09 AM
Posted by: zicjin | (30) November 24, 2013 05:27 PM
Posted by: Rockee | (29) April 21, 2013 08:45 PM
Posted by: 幻の上帝 | (28) April 14, 2013 09:39 AM
Posted by: water | (27) April 3, 2013 11:55 PM
Posted by: sm | (26) April 3, 2013 09:25 AM
Posted by: 萤点博客 | (25) April 2, 2013 01:44 PM
Posted by: chain | (24) April 2, 2013 01:23 PM
Posted by: licheng | (23) April 2, 2013 11:50 AM
Posted by: free | (22) March 27, 2013 12:24 AM
Posted by: w | (21) March 26, 2013 03:08 PM
Posted by: zxhfirefox | (20) March 24, 2013 11:30 PM
Posted by: swz | (19) March 24, 2013 03:45 AM
Posted by: swz | (18) March 24, 2013 03:42 AM
Posted by: dogfeet | (17) March 23, 2013 12:22 AM
Posted by: JiangHu | (16) March 22, 2013 10:34 PM
Posted by: Frank | (15) March 22, 2013 10:52 AM
Posted by: 吕子熏 | (14) March 21, 2013 02:22 PM
Posted by: omega | (13) March 21, 2013 09:55 AM
Posted by: 吕子熏 | (12) March 20, 2013 01:45 PM
Posted by: G_will | (11) March 20, 2013 12:32 PM
Posted by: tonyzzp | (10) March 20, 2013 10:04 AM
Posted by: wavekuan | (9) March 19, 2013 09:24 PM
Posted by: guest | (8) March 19, 2013 05:19 PM
Posted by: paladin_t | (7) March 19, 2013 04:47 PM
Posted by: 四不象 | (6) March 19, 2013 04:18 PM
Posted by: Kimmy Leo | (5) March 19, 2013 04:10 PM
Posted by: midful | (4) March 19, 2013 04:07 PM
Posted by: tony | (3) March 19, 2013 03:48 PM
Posted by: tony | (2) March 19, 2013 03:47 PM
Posted by: wencan | (1) March 19, 2013 03:03 PM