Objective-C对象之类对象和元类对象(一)

原创 2013年02月19日 23:44:05

Objective-C对象之类对象和元类对象(一)

作者:wangzz
原文地址:http://blog.csdn.net/wzzvictory/article/details/8592492
转载请注明出处
如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号wangzzstrive来支持我,谢谢!

作为C语言的超集,面向对象成为Objective-C与C语言的最大区别,因此,对象是Objective-C中最重要的部分之一。目前面向对象的语言有很多,Objective-C中的对象又和其他语言中的对象有什么区别呢?下面来简单介绍Objective-C中对象的实现。
1、Objective-C中的类

谁都知道,所有的对象都是由其对应的类实例化而来,殊不知类本身也是一种对象,先不要对这句话感到惊讶。
首先我们来关注Objective-C中的类。在Objective-C中,我们用到的几乎所有类都是NSObject类的子类,NSObject类定义格式如下(忽略其方法声明):
@interface NSObject <NSObject> {
Class isa;
}
这个Class为何物?在objc.h中我们发现其仅仅是一个结构(struct)指针的typedef定义:
typedef struct objc_class *Class;
同样的,objc_class又是什么呢?在Objective-C2.0中,objc_class的定义如下:
struct objc_class {
Class isa;
}
写到这里大家可能就晕了,怎么又有一个isa??这些isa到底是什么?之间有什么区别和联系?接下来解答这一连串的疑问。
其实在Objective-C中任何的类定义都是对象。即在程序启动的时候任何类定义都对应于一块内存。在编译的时候,编译器会给每一个类生成一个且只生成一个”描述其定义的对象”,也就是苹果公司说的类对象(class object),他是一个单例(singleton), 而我们在C++等语言中所谓的对象,叫做实例对象(instance object)。对于实例对象我们不难理解,但类对象(class object)是干什么吃的呢?我们知道Objective-C是门很动态的语言,因此程序里的所有实例对象(instace object)都是在运行时由Objective-C的运行时库生成的,而这个类对象(class object)就是运行时库用来创建实例对象(instance object)的依据。
再回到之前的问题,肿么这个实例对象(instance object)的isa指针指向的类对象(class object)里面还有一个isa呢?这个类对象(class objec)的isa指向的依然是一个objc-class,它就是“元类对象”(metaclass object),它和类对象(class object)的关系是这样的:

2、类对象(class object)
①类对象的实质
我们知道了:类对象是由编译器创建的,即在编译时所谓的类,就是指类对象(官方文档中是这样说的: The class object is the compiled version of the class)。任何直接或间接继承了NSObject的类,它的实例对象(instance objec)中都有一个isa指针,指向它的类对象(class object)。这个类对象(class object)中存储了关于这个实例对象(instace object)所属的类的定义的一切:包括变量,方法,遵守的协议等等。因此,类对象能访问所有关于这个类的信息,利用这些信息可以产生一个新的实例,但是类对象不能访问任何实例对象的内容。
当你调用一个 “类方法” 例如 [NSObject alloc],你事实上是发送了一个消息给他的类对象。

②类对象和实例对象的区别
当然有区别了,尽管类对象保留了一个类实例的原型,但它并不是实例本身。它没有自己的实例变量,也不能执行那些类的实例的方法(只有实例对象才可以执行实例方法)。然而,类的定义能包含那些特意为类对象准备的方法–类方法( 而不是的实例方法)。类对象从父类那里继承类方法,就像实例从父类那里继承实例方法一样。
③类对象与类名
在源代码中,类对象由类名表示。
在下面的例子中,Retangle类 用从NSObject那里继承来的方法来返回类的版本号:
int versionNumber = [Rectangle version];
只有在消息表达式中作为接收者,类名才代表类对象。其他地方,你需要要求一个实例或者类返回class id。 响应class消息:
id aClass = [anObject class];
id rectClass = [Rectangle class];
如同上面的例子显示的那样,类对象像其他对象一样,也是id类型。

总之,类对象是一个功能完整的对象,所以也能被动态识别(dynamically typed),接收消息,从其他类继承方法。特殊之处在于它们是由编译器创建的,缺少它们自己的数据结构(实例变量),只是在运行时产生实例的代理。

3、元类对象(metaclass object)
①元类对象的实质
实际上,类对象是元类对象的一个实例!!元类描述了 一个类对象,就像类对象描述了普通对象一样。不同的是元类的方法列表是类方法的集合,由类对象的选择器来响应。当向一个类发送消息时,objc_msgSend会通过类对象的isa指针定位到元类,并检查元类的方法列表(包括父类)来决定调用哪个方法。元类代替了类对象描述了类方法,就像类对象代替了实例对象描述了实例化方法。
很显然,元类也是对象,也应该是其他类的实例,实际上元类是根元类(root class’s metaclass)的实例,而根元类是其自身的实例,即根元类的isa指针指向自身。
类的super_class指向其父类,而元类的super_class则指向父类的元类。元类的super class链与类的super class链平行,所以类方法的继承与实例方法的继承也是并行的。而根元类(root class’s metaclass)的super_class指向根类(root class),这样,整个指针链就链接起来了!!

记住,当一个消息发送给任何一个对象, 方法的检查 从对象的 isa 指针开始,然后是父类。实例方法在类中定义, 类方法 在元类和根类中定义。(根类的元类就是根类自己)。在一些计算机语言的原理中,一个类和元类层次结构可以更自由的组成,更深元类链和从单一的元类继承的更多的实例化的类。Objective-C 的类方法 是使用元类的根本原因,在其他方面试图在隐藏元类。例如 [NSObject class] 完全相等于 [NSObject self],所以,在形式上他还是返回的 NSObject->isa 指向的元类。 Objective-C语言是一组实用的折中方案。

还有些不明白? 下面这个图标可能会有些帮助:



综上所述,类对象(class object)中包含了类的实例变量,实例方法的定义,而元类对象(metaclass object)中包括了类的类方法(也就是C++中的静态方法)的定义。类对象和元类对象中当然还会包含一些其它的东西,苹果以后也可能添加其它的内容,但对于我们只需要记住:类对象存的是关于实例对象的信息(变量,实例方法等),而元类对象(metaclass object)中存储的是关于类的信息(类的版本,名字,类方法等)。要注意的是,类对象(class object)和元类对象(metaclass object)的定义都是objc_class结构,其不同仅仅是在用途上,比如其中的方法列表在类对象(instance object)中保存的是实例方法(instance method),而在元类对象(metaclass object)中则保存的是类方法(class method)。关于元类对象可以参考苹果官方文档" The Objective-‐C Programming Language "

4、类对象和元类对象的相关方法

①object_getClass跟随实例的isa指针,返回此实例所属的类,对于实例对象(instance)返回的是类(class),对于类(class)则返回的是元类(metaclass),
②-class方法对于实例对象(instance)会返回类(class),但对于类(class)则不会返回元类(metaclass),而只会返回类本身,即[@"instance" class]返回的是__NSCFConstantString,而[NSString class]返回的是NSString。
③class_isMetaClass可判断某类是否为元类.                                     

④使用objc_allocateClassPair可在运行时创建新的类与元类对,使用class_addMethod和class_addIvar可向类中增加方法和实例变量,最后使用objc_registerClassPair注册后,就可以使用此类了。看到动态语言牛逼的地方了吗,可以在需要时更改已经定义好的类!Objective-C的类别方法估计底层就是这么实现的,只是不知道为什么类别不能增加实例变量,有高手请留言。

----by wangzz


相关文章推荐

Objective-C对象模型--类对象和元类对象

参考: Objective-C对象之类对象和元类对象(一) Objective-C对象模型及应用 参看以上文章基本可以了解Objective-C对象模型模型了, 可做学习: ...
  • iunion
  • iunion
  • 2015年07月15日 10:41
  • 2969

Object-C中的类-类的声明

1.关键字命名:为了避免与已有的c,C++关键字冲突,ObjectC关键字都有@开始,如:@classs,@interface,@private,@try,@catch,@protocol等。 2...

object-c如何创建一个简单的类

这个实例为我们展示了在object-c中,如何创建和使用类(class),不要忘记,object-c是面向对象的啊。 Fraction,,正如它的含义所在一样,这个程序只提供了打印分数的例子。 1....
  • liranke
  • liranke
  • 2013年07月27日 09:02
  • 2970

object-c 学习第二天(类对象和方法)

学习语言我是在官方的英语文档上,当然也有很多中文的文档也很不错,可是我懒得找了,这个是官方的链接https://developer.apple.com/library/mac/#referenceli...

java中类、对象、实例的关系

java中类、对象、实例的关系 (刚刚接触java,难免有许多错误,欢迎指正) java作为面向对象编程语言,作为初学者首先要分清类、对象、实例之间的关系是必要的。 正所谓物以类聚,类就是...

Java类和对象及实例

1,类和对象在面向对象的概念当中,类(class)是既包括数据又包括作用于数据的一组操作的封装体。类的数据称为成员变量,类对数据的操作称为成员方法。成员变量反映类的状态和特征,成员方法反映类的行为和能...

Objective-C Runtime 运行时之一:类与对象

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时能够更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交...

墨半成霜为您深入剖析UIViewController与UIView(一)

如果你对UIViewController的理解仅限于:一个UIViewController 可以push/pop/present到另外一个ViewController,并且给UIView提供容器的话,...

OCUI界面设计:基础控件(二)

开关控件 UISwitchUISlider一般使用在功能的开启或关闭、是与否的选择等方面。其展示效果如下:初始化- (instancetype)initWithFrame:(CGRect)frame;...

Objective-C学习笔记(四):OC之分类、类对象、description方法和SEL

一、Category 分类       1.分类的创建          1>首先按照学习笔记(一)中的方法创建一个新的命令行项目          2>new file新建一个文件         ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Objective-C对象之类对象和元类对象(一)
举报原因:
原因补充:

(最多只允许输入30个字)