Objective-C 对象模式深入分析

The Objective-C object model

作为一名Objective-C的软件开发者,你可以在不需要理解Objective-C的鼻祖C语言和Objective-C所采用的对象模型的情况下,依然能够完成许多的工作。事实上,因为这些特性的确很复杂,要去学习这些个对象模型可能会令你感到望而却步。

虽然这个问题的确比较复杂,但是还是有努力去学习它的必要性的,因为你最终还是会需要和Objective-C运行时的情况打交道的,而那个时候理解了对象模型将会帮助你更好地解决此类问题。

端起一杯茶,或者一杯咖啡,跟着我一起来探索Objective-C的对象模型吧。

对象是类的实例

看起来这个是很明显的,但是我们不妨花些时间来认真思考一下当我们说“一个对象是一个类的实例”的时候,这句话意味着意味着什么。以下面的代码举例说明。

NSString *name = [NSString stringWithFormat:@"%@", @"Peter"];

这个代码看起来更像是人造的,而不是实际使用需要的一段代码,但是它对于展示Objective-C运行时的具体工作方式是很重要的。当上述代码执行完毕后,我们最终获取到的是一个叫做name的变量,该变量是NSString类的一个实例,请细想一下以下知识:

  • 对象(类的实例)是用来保存状态的
  • 一个对象的状态保存在它的实例变量内。比如,上述代码中的name变量分配了一些内存用来保存字符串内容"Peter"
  • name变量同时也包含了一个指向它所在的类(NSString)的指针
  • Objective-C里面,对象不包含任何方法(行为),仅仅保存着状态信息
  • 类只包含方法,不包含任何状态信息。这些包含的方法是他们的实例能够响应的方法(即实例方法)
  • 为了使得我们清楚一些,我们再重复一遍:对象包含了保存的状态(即实例变量),而类包含了保存的行为(方法)

为了使得表述更加具体,我们来看看下面的图标:

实例方法图

上图中蓝色的框框表示name变量(类NSString的一个实例)。根据上图所示,让我们来看一下,如果你向变量name发送length的消息,那么会发生什么?

NSUInteger len = [name length];
  1. 首先Objective-C会询问变量name是哪个类的实例,因为所有的方法都包含在类里面,所以从那里面才能开始寻找方法length在哪。
  2. 因为name是类NSString的实例变量,所以Objective-C将会先找到类NSString,然后开始查找方法length。
  3. 如果Objective-C在类NSString里面找到了方法length,那么它就会停止查找并开始执行方法。否则,它就会根据类的继承关系继续查找。

需要说明一点的是,上面所描述的过程是经过我的简化的,我没有考虑方法存储的其他情况。(比如Objective-C的分类)

类也是对象

既然类能够保存它的实例的方法(实例方法),那么类方法保存在哪里呢?我们再来看看创建变量name的代码:

NSString *name = [NSString stringWithFormat:@"%@", @"Peter"];

上述代码中,消息stringWithFormat:是向类NSString发送的。类可以接收消息吗?如果可以,那么那些方法保存在哪里呢?事实上是这样的,Objective-C的语法隐藏了一些东西,他隐藏了类也是对象的事实。

如果类NSString是一个对象,那就意味着它一定是从一个保存着它的方法的类实例化来的。这个猜测是对的,不过在深入这个问题之前,我们再来看一段代码:

@interface Person : NSObject {}
+ (void) aClassMethod;
- (void) anInstanceMethod;
@end

也许你看过这种类似的代码很多很多,但是这这段代码干嘛的?

  • 声明了一个类,该类是Person
  • 这个类用来保存实例方法
  • 在这段代码的背后也创建了另外的一个类,不幸的是这个额外的类名也是Person,只不过它是Person元类而已
  • Person元类会保存着Person的类方法

看起来现在的问题越来越复杂了,因为相同的名字用了一遍又一遍,回到最初的变量name上来讨论,我们可以说:

  • 变量name是类NSString的一个实例
  • 类NSString是一个NSString元类实例化的一个对象
  • 如果你向对象name发送消息length,那么Objective-C会去类NSString查找这个方法
  • 如果你向对象NSString发送stringWithFormate:消息,Objective-C会在NSString元类里面查找这个方法
  • NSString是一个类,也是一个对象,类也是一个对象

这里是另外一个类图示意图

元类方法(类方法)图

这一次,蓝色的框框表示的是NSString对象,我们再来看看创建name对象的代码:

NSString *name = [NSString stringWithFormat:@"%@", @"Peter"];

当向对象NSString发送消息stringWithFormate:的时候,Objective-C将会:

  1. 询问NSString对象是哪个类的一个实例,哪一个是它的元类
  2. 开始在NSString的元类里面查找方法stringWithFormate:,如果没找到,它会继续根据类的类的继承关系继续查找

当然,因为NSString继承自NSObject,所以NSString元类继承自NSObject元类。

奇怪的NSObject继承

如果到了这里你还算清醒的话,那么利用你现在所掌握的关于Objective-C对象模型的知识够你去了解你的代码在运行时会发生了什么。可能还有一个问题你想知道:为了么NSObject元类好像继承自NSObject类?这是因为本来就是这样子的。

考虑一下以下情况:

  • NSObject为它的实例保存着方法(保存实例方法)
  • NSObject元类为类NSObject保存着方法。(保存类方法)
  • NSObject元类继承自非元类NSObject
  • 因此,NSObject的实例方法也是类方法,这些方法在所有Objective-C的元类方法的查找路径中

有点奇怪,但是如果你再去看看上面的图,你就应该会更清楚些了。

时间: 2024-07-30 16:38:27

Objective-C 对象模式深入分析的相关文章

空对象模式(Null Object Pattern)

空对象模式:用一个空对象来取代null实例的检查,空对象实现一个不做任何动作的关系.(消除如if(Object == null) 这样的检查null实例代码) 例子: public abstract class Duck { public String name; public abstract void getName(); } public class ConcreteDuck extends Duck { public ConcreteDuck(String name) { this.na

C# 设计模式之空对象模式

最近看了不少的书籍和视频等相关资料,决定自己边学习边写一下个人对设计模式的理解,如果有不对的请大家多多指正. 今天先说说我个人觉得最简单的设计模式 -- [空对象模式] 空对象模式可以减少客户端对对象判断是否为空的重复操作,也可以减少异常发生的情况[如果客户端调用程序忘记了检查对象是否为空,而直接访问对象中的数据,则有可能会报出异常,影响程序运行]. 废话不说了,先上我写的代码,下面是未运用空对象模式之前的示例代码: 要返回的实体代码,Person.cs: namespace NullObjec

空对象模式

在学习Head First设计模式中的“命令模式”过程中,偶然发现可以用在coding过程中的小技巧.赶紧记录,以备后用! 具体可以称之为“空对象”模式,而且专门用来处理对象为null的情形. 比如以下情形: Command接口: public interface Command { public void execute(); } 测试代码: Command[] commands = new Command[10]; // initial commands[0] and the others

角色对象模式

意图 单个对象透过不同的角色对象来满足不同客户的不同需求.每一个角色对象针对不同的客户内容来扮演其角色.对象能够动态的管理其角色集合.角色作为独立的对象是的不同的内容能够简单的被分离开来,系统间的配置也变得容易. 译注:为了行文的流畅性及内容意思的准确性,尽量贴近原文使用英文单词标记特定内容, 如Customer表示客户,Client表示客户端,Component表示组件等.因为有各种图例说明,所以在图例说明时,使用原题中的英文单词对应图中内容.有时也中英文交叉使用.因为网页显示的问题,中文黑体

【设计模式】空对象模式

在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查.Null 对象不是检查空值,而是反应一个不做任何动作的关系.这样的 Null 对象也可以在数据不可用的时候提供默认的行为. 在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方. 实现 我们将创建一个定义操作(在这里,是客户的名称)的 AbstractCustomer 抽象类,和扩展了 Abs

被遗忘的设计模式——空对象模式(Null Object Pattern)

GoF(四人帮)那本<设计模式 可复用面向对象软件的基础>可谓是设计模式方面的经典之作,其中介绍的23种设计模式, 也可谓是经典中的经典.但是,设计模式的种类绝不仅仅是这23种,除此之外还有很多巧妙可爱的设计模式值得我们学习.这些 被遗忘的设计模式,也可以堪称经典之作.今天我们来一起学习被遗忘的设计模式--空对象模式(Null Object Pattern). 一起看看这个模式会带给我们怎样的惊喜? 一.Pattern name Provide an object as a surrogate

【设计模式】数据访问对象模式

数据访问对象模式(Data Access Object Pattern)或 DAO 模式用于把低级的数据访问 API 或操作从高级的业务服务中分离出来.以下是数据访问对象模式的参与者. 数据访问对象接口(Data Access Object Interface) - 该接口定义了在一个模型对象上要执行的标准操作. 数据访问对象实体类(Data Access Object concrete class) - 该类实现了上述的接口.该类负责从数据源获取数据,数据源可以是数据库,也可以是 xml,或者

面向对象为什么要多用对象模式而少用继承模式?

进来学习java的时候遇到了一些经验说多用对象模式,少用继承模式.现在写一点感想. 面向对象的对象之间的哦和方式有继承,实现,关联,依赖,聚合和组合.其中的继承和实现是继承这类模式. 说道的一个原因就是代码污染.例如一个父类非常复杂.而一个继承了这个类的子类可能重写了一部分的方法.但是继承了全部的方法.用户在使用继承的子类的时候可能会调用没有重写的父类的方法并且如果这种方法是在子类的设计者的意图之外的操作,那么子类在继承父类的时候,可以认为不光是继承到了有用的功能,还继承到了垃圾功能,父类的代码

ACE主动对象模式(1)

转载于:http://www.cnblogs.com/TianFang/archive/2006/12/11/589168.html 主动对象模式用于降低方法执行和方法调用之间的耦合.该模式描述了另外一种更为透明的任务间通信方法. 传统上,所有的对象都是被动的代码段,对象中的代码是在对它发出方法调用的线程中执行的,当方法被调用时,调用线程将阻塞,直至调用结束.而主动对象却不一样.这些对象具有自己的命令执行线程,主动对象的方法将在自己的执行线程中执行,不会阻塞调用方法. 例如,设想对象"A&quo