该内容是个人理解,若有偏差,希望大神可以指点一二,在下感激不尽
在讲解前,先我说发现的两个现象:
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之间的关系
说到这里 必须上图了:
那么 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