OC---类的深入研究-类的本质
OC类的本质
类本身也是个对象,是个Class类型的对象,简称类对象
类名就代表类对象 也就是代表类(类 就是 类对象\类名; 类对象\类名 就是 类)
每个类只有一个类对象
typedef struct objc_class *Class;
[对象名 class]; 或者[类名 class]; 返回类(类对象\类名)
void test()
{
Person *p1 = [[Person alloc] init];
Person *p2 = [[Person alloc] init];
Class c1 = [p1 class];
Class c2 = [p2 class];
Class c3 = [Person class];
// c1 == c2 == Person c1、c2、c3都代表 类(类对象\类名)---Person
Class c5 = [[[[[[c1 alloc] init] class] alloc] init] class]; // c5还是代表Person这个类的类对象
Class c6 = [[[[[[c3 alloc] init] class] alloc] init] class]; // c6还是代表Person这个类的类对象
NSLog(@"c1==%p, c2==%p, c2==%p, c5==%p, c6==%p",c1, c2, c3, c5, c6);
}
调用test函数输出的结果c1==0x100001118, c2==0x100001118, c2==0x100001118, c5==0x100001118, c6==0x100001118
+ (void)load方法和+ (void)initialize—类的加载和初始化
在类被加载(只会被加载一次)的时候,系统会自动调用 继承自NSObject类的 + (void)load方法;自己可以在自定义的类.m文件@implementation中重写+ (void)load方法监测类何时被加载
先加载父类,再加载子类(程序运行类就会被加载,类只会被加载一次)
当第一次使用这个类的时候,系统会自动调用一次继承自NSObject类的 + (void)initialize方法
总结:
1> 当程序启动的时候,就会加载一次项目中所有的类(和分类),类(和分类)加载完毕后,系统会自动调用一次每个(类和分类) + (void)load方法。只会调用一次。———先加载原始类,再加载分类
2> 当第一次使用这个类的时候,系统会自动调用当前t类的 + (void)initialize方法
3> 先加载父类,再加载子类(先调用父类的+ load方法,再调用子类的+ load方法);
先初始化父类,再初始化子类(先调用父类的+ initialize方法,再调用子类的initialize方法)—如果有分类,就只调用分类的+ initialize方法,不会调用自己的+ initialize方法
4> 如果想在类第一次被使用(初始化)的时候监听一些操作,做一些事情,可以重写该类的+ (void)initialize
description方法---java的toString()
- description方法
使用NSLog和%@输出某个对象时,会调用对象的- description方法,并拿到返回值输出(系统自定义的返回值是--- <类名:对象的内存地址>)
+ description方法
使用NSLog和%@输出某个类对象时,会调用类对象的+ description方法,并拿到返回值输出(系统自定义的返回值是 ---类名)
description方法相当于java的toString(),一般会重写- description方法输出对象的属性
SEL(方法的包装类型)
1. 方法的存储位置
1> 每个类的方法列表都存储在类对象中
2> 每个方法都有一个与之对应的SEL类型的数据(对象)
3> 根据一个SEL类型的数据(对象)就可以找到方法的地址,进而调用方法
4> SEL类型的定义
typedef struct objc_selector *SEL;
2. SEL对象的建的2中方式
// 创建SEL类型的数据(对象)的2中方式
SEL s = @selector(test); // 方法名为 test
SEL s2 = NSSelectorFromString(@"test:"); // 方法名为 test:
Person *p = [[Person alloc] init];
[p test];
[p performSelector:s];
[p performSelector:NSSelectorFromString(@"test")];
[p test:@“aaa"];
[p performSelector:NSSelectorFromString(@"test:") withObject:@“aaa"];
[p performSelector:@selector(test:) withObject:@“aaa”];
[p performSelector:s2 withObject:@“aaa”];
每个方法内部都有一个内置的SEL类型的数据_cmd 代表着当前方法
- (void)test1
{
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"%@", str); // _cmd == @selector(test1)
}
// 输出结果为 test1
总结:
SEL其实是对方法的一种包装,将方法包装为一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法