码迷,mamicode.com
首页 > 其他好文 > 详细

OC类的本质及分类

时间:2015-10-19 15:18:36      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:

(一)类的本质

  • 类对象(class object)与实例对象(instance object) 

类本身也是一个对象,是class类型的对象,简称“类对象”。

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

Class 是一个 objc_class 结构类型的指针;而 id(任意对象)是一个 objc_object 结构类型的指针, 其第一个成员是一个 objc_class 结构类型的指针。注意这里有一关键的引申解读:内存布局以一个 objc_class 指针为开始的所有东东都可以当做一个 object 来对待! 那 objc_class 又是怎样一个结 构体呢?且看:

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

 

objc_class 又是怎样一个结 构体呢? 

 1 struct objc_class { 

3 struct objc_class* isa; 4 struct objc_class* super_class; 5 const char* name; 6 long version; 7 long info;//供运行期使用的一些位标识。有如下一些位掩码:CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含实例方法和变量; 8       //CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法; 10       //CLS_METHOD_ARRAY (0x100L) 该标志位指示 methodlists 是指向一个 objc_method_list 还是 一个包含 objc_method_list 指针的数组; 11 12 long instance_size;//该类的实例变量大小(包括从父类继承下来的实例变量) 14 struct objc_ivar_list* ivars;//指向 objc_ivar_list 的指针,存储每个实例变量的内存地址,如果该类没有任何实例变量则为NULL 16 struct objc_method_list** methodLists; //与 info 的一些标志位有关,CLS_METHOD_ARRAY 标识位决定其指向的东西(是指 向单个 objc_method_list 还是一个                           //objc_method_list 指针数组),如果 info 设置了 CLS_CLASS 则 objc_method_list 存储实例方法, 18                      //如果设置的是 CLS_META 则存储类方法 20 struct objc_cache* cache; //指向 objc_cache 的指针,用来缓存最近使用的方法,以??高效率; 22 struct objc_protocol_list* protocols;//指向 objc_protocol_list 的指针,存储该类声明要遵守的正式协议 24 };

 

类对象中的 isa 指向类结构 被称作 metaclass,metaclass 存储类的 static 类成员变量与 static 类成员方法(+开头的方法);实 例对象中的 isa 指向类结构称作 class(普通的),class 结构存储类的普通成员变量与普通成员方法(- 开头的方法)。 

 

  • 在继承层次中,子类,父类,根类(这些都是普通 class)以及其对应的 metaclass 的 isa 与 super_class 之间关系:

规则一:类的实例对象的 isa 指向该类;该类的 isa 指向该类的 metaclass;
规则二:类的 super_class 指向其父类,如果该类为根类则值为 NULL;
规则三:metaclass 的 isa 指向根 metaclass,如果该 metaclass 是根 metaclass 则指向自身;

规则四:metaclass 的 super_class 指向父 metaclass,如果该 metaclass 是根 metaclass 则指向 该 metaclass 对应的类; 

技术分享

  • 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"];

  • 总结:

ObjC 为每个类的定义生成两个 objc_class ,一个即普通的 class,另一个即 metaclass。我们可以在 运行期创建这两个 objc_class 数据结构,然后使用 objc_addClass 动态地创建新的类定义 

 

(二)类的加载和初始化

 

 1 #import "Person.h"
 2 
 3 @implementation Person
 4 
 5 
 6 +(void)load
 7 {
 8     NSLog(@"%s",__func__);
 9 }
10 
11 +(void)initialize
12 {
13     NSLog(@"%s",__func__);
14 }
15 @end
 1 #import "Student.h"
 2 
 3 @implementation Student
 4 +(void)load
 5 {
 6     NSLog(@"%s",__func__);
 7 }
 8 
 9 +(void)initialize
10 {
11     NSLog(@"%s",__func__);
12 }
13 @end

 

测试程序:

 

 1 int main(int argc, const char * argv[]) {
 2     @autoreleasepool {
 3         // insert code here...
 4         NSLog(@"Hello, World!");
 5         
 6         Person* p1=[Person new];
 7         
 8 //      Person* p2=[Person new];//注释掉结果不变
 9         
10         Student* s1=[Student new];
11         
12     }
13     return 0;
14 }

运行结果:

2015-10-19 14:15:11.614 TClass[2447:116989] +[Person load]

2015-10-19 14:15:11.615 TClass[2447:116989] +[Student load]

2015-10-19 14:15:11.616 TClass[2447:116989] Hello, World!

2015-10-19 14:15:11.616 TClass[2447:116989] +[Person initialize]

2015-10-19 14:15:11.616 TClass[2447:116989] +[Student initialize]

 

总结:

1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法,只会调用一次;

2.当第一次使用某个类时,就会调用当前类的+initialize方法;

3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法,最后调用分类的+load方法),先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)。

4.注意:在初始化的时候,如果在分类中重写了+initialize方法,则会覆盖掉父类的。

5.重写+initialize方法可以监听类的使用情况。

 

(三)分类

分类的作用:在不改变原来的类内容的基础上,为类增加一些方法。

在分类中添加一个方法

 技术分享

Study方法的实现

 技术分享

(二)分类的使用注意

(1)分类只能增加方法(包括类方法和对象方法),不能增加成员变量

(2)在分类方法的实现中可以访问原来类中的成员变量;

(3)分类中可以重新实现原来类中的方法,但是会覆盖掉原来的方法,导致原来的方法无法再使用(警告)

(4)方法调用的优先级:分类->原来的类->父类,若包含有多个分类,则最后参与编译的分类优先;

(5)在很多的情况下,往往是给系统自带的类添加分类,如NSObject和NSString,因为有的时候,系统类可能并不能满足我们的要求。

(6)在大规模的应用中,通常把相应的功能写成一个分类,可以有无限个分类,对原有类进行扩充,一般分模块写,一个模块一个分类。

 

OC类的本质及分类

标签:

原文地址:http://www.cnblogs.com/H7N9/p/4891849.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!