类的本身也是一个对象----isa指针详解

该内容是个人理解,若有偏差,希望大神可以指点一二,在下感激不尽

在讲解前,先我说发现的两个现象:

1、网格视图的自定义cell需要提前注册(Swift)

        collectionView.registerClass(MyCell.self, forCellWithReuseIdentifier: "qqq")

//其中MyCell是我自定义的cell类,注册函数的第一个参数是AnyClass?就是一个类类型对象。

2、判断segue推出的界面属于哪个类(Object-C)

    if ([segue.destinationViewController class] == RegistViewController.self) {  }

//[segue.destinationViewController class] 是segue推出界面对象所属的类,RegistViewController.self的意思是RegistViewController类本身,可以抽象的理解他为类对象。

大家都知道,对象是对客观事物的抽象,类是对对象的抽象。我们经常举的例子,狗和猫都是动物,此时动物就是类,狗和猫是具体的对象。从上面两个例子,我想到,当动物和植物放到一起时,就是生物类的对象。所以,动物类其实也可以是对象,是生物类的具体。这才符合对象是对客观事物的抽象,类是对对象的抽象的道理,只是有时候分类的层级不同,就类似于不在一个维度上。
当然,也许很多人早就知道这点,这样想来是我之前理解的太片面,在此我分享给又跟我一样迷惑的人,也希望理解此问题比较深刻的前辈,多多指教。

对,我得拿点证据来证明啊.Come on!!

与C++相比,ObjC中的类与对象结构要简洁与一致的多,那么我就先来说说ObjC中类与对象的结构

我们可以在我们可以在/usr/include/objc/objc.h 和 runtime.h 中找到对 class 与 object 的定义:

typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id;

Class是一个objc_class结构类型的指针;而id(任意对象)是一个objc_object结构类型的指针,其第一个成员是一个objc_class结构类型的指针. 这里有这样一个关键的概念: 内存布局以一个objc_class指针为开始的所有东东都可以当做一个object来对待!
我们再来看看objc_class的结构:

struct objc_class
{
    struct objc_class* isa;    //指向metaClass
    struct objc_class* super_class;   //指向其父类
    const char* name;   //类名
    long version;    // 类的版本信息,初始化默认为0,
    long info;   // 一些标识信息,区分普通类还是元类
    long instance_size;   //该类的实例变量大小(包括继承来的)
    struct objc_ivar_list* ivars;   //用于存储每个成员变量的地址
    struct objc_method_list** methodLists;   //方法列表
    struct objc_cache* cache;   //指向最近使用的方法的指针,提高效率
    struct objc_protocol_list* protocols;   //储存该类遵守的协议
};

isa: 是一个objc_class类型的指针. 根据上面内存布局以一个objc_class指针为开始的所有东东都可以当做一个object来对待! 也就是说objc_class或者说类其实也可以当做一个objc_class对象来对待! 对象是对象,类也是对象. 其实ObjC中已经帮我们直接区分这两钟不同的对象: 类对象(class object)实例对象(instance object). 我们用这两个术语来区分不同的对象,而使用”对象”这一术语来泛指所有的对象. 每个实例对象有个isa的指针,他指向对象的类,class 结构存储类的普通成员变量与普通成员方法(-开头的方法); 而Class里也有个isa的指针, 指向metaClass(元类)。元类存储类的static类成员变量与static类成员方法(+开头的方法)。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(metaClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root metaClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。

super_class: 指向该类的父类,如果该类的父类已经是最顶层的根类(如NSObject 或 NSProxy),那么super_class 就为 NULL.

先中断一下其他类结构成员的介绍, 让我们缕一下在继承层次中,子类,父类,根类(普通的类)以及元类的isa与super_class之间的关系

  1. 类的实例对象的isa 指向该类; 该类的isa指向该类的元类
  2. 类的super_class指向其父类, 如果该类为根类则值为NULL
  3. 元类(metaclass)的isa指向根元类,如果该元类是根元类,则指向自身
  4. 元类的super_class指向父元类,如果该元类是根元类,则指向该元类对应的类;

说到这里 必须上图了:

这里写图片描述

那么 class 与 metaclass 有什么区别呢?

class 是 instance object 的类类型。当我们向实例对象发送消息(实例方法)时,我们在该实例对象的 class 结构的 methodlists 中去查找响应的函数,如果没找到匹配的响应函数则在该 class 的父类中的 methodlists去查找(查找链为上图的中间那一排)。如下面的代码中,向str 实例对象发送 lowercaseString 消息,会在 NSString 类结构的 methodlists 中去查找 lowercaseString 的响应函数。

NSString * str; [str lowercaseString];

metaclass 是 class object 的类类型。当我们向类对象发送消息(类方法)时,我们在该类对象的 metaclass 结构的methodlists 中去查找响应的函数,如果没有找到匹配的响应函数则在该 metaclass 的父类中的 methodlists去查找(查找链为上图的最右边那一排)。如下面的代码中,向 NSString 类对象发送 stringWithString 消息,会在NSString 的 metaclass 类结构的 methodlists 中去查找 stringWithString 的响应函数。

[NSString stringWithString:@"str"];

好,至此我们明白了类的结构层次,让我们接着看类结构中的其他成员。

name:一个 C 字符串,指示类的名称。我们可以在运行期,通过这个名称查找到该类(通过:id objc_getClass(const char *aClassName))或该类的 metaclass(id objc_getMetaClass(const char *aClassName));

version:类的版本信息,默认初始化为 0。我们可以在运行期对其进行修改(class_setVersion)或获取(class_getVersion)。

info:供运行期使用的一些位标识。有如下一些位掩码:
CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含实例方法和变量;
CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;
CLS_INITIALIZED (0x4L) 表示该类已经被运行期初始化了,这个标识位只被 objc_addClass 所设置;
CLS_POSING (0x8L) 表示该类被 pose 成其他的类;(poseclass 在ObjC 2.0中被废弃了);
CLS_MAPPED (0x10L) 为ObjC运行期所使用
CLS_FLUSH_CACHE (0x20L) 为ObjC运行期所使用
CLS_GROW_CACHE (0x40L) 为ObjC运行期所使用
CLS_NEED_BIND (0x80L) 为ObjC运行期所使用
CLS_METHOD_ARRAY (0x100L) 该标志位指示 methodlists 是指向一个 objc_method_list 还是一个包含 objc_method_list 指针的数组;

instance_size:该类的实例变量大小(包括从父类继承下来的实例变量);

ivars:指向 objc_ivar_list 的指针,存储每个实例变量的内存地址,如果该类没有任何实例变量则为 NULL;

methodLists:与 info 的一些标志位有关,CLS_METHOD_ARRAY 标识位决定其指向的东西(是指向单个 objc_method_list还是一个 objc_method_list 指针数组),如果 info 设置了 CLS_CLASS 则 objc_method_list 存储实例方法,如果设置的是 CLS_META 则存储类方法;

cache:指向 objc_cache 的指针,用来缓存最近使用的方法,以提高效率;

protocols:指向 objc_protocol_list 的指针,存储该类声明要遵守的正式协议。

原文见http://blog.csdn.net/kesalin/article/details/7211228

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值