实例(instance)对象
实例对象是通过alloc出来的对象,每次alloc都会产生一个新的实例对象;实例对象的存储信息:
- isa指针
- 其他的成员变量
- ...
NSObject *obj1 = [[NSObject alloc] init]; NSObject *obj2 = [[NSObject alloc] init];
obj1和obj2是NSObject的实例对象,是两个不同的对象,占据着两块不同的内存空间;
类(class)对象
每个类在内存中有且只有一个class对象;类对象的存储信息:
- isa指针
- superclass指针
- 类的属性信息(@property)
- 类的对象方法信息(instancemethod)
- 类的协议信息(protocol)
- 类的成员变量信息(ivar)
- ...
Class objCls1 = [obj1 class]; Class objCls2 = [obj2 class]; Class objCls3 = [NSObject class]; Class objCls4 = object_getClass(obj1); Class objCls5 = object_getClass(obj2); Class objCls6 = objc_getClass("NSObject"); NSLog(@"实例对象 - %p - %p", obj1, obj2); NSLog(@"类对象 - %p - %p - %p - %p - %p - %p", objCls1, objCls2, objCls3, objCls4, objCls5, objCls6);
运行结果
实例对象 - 0x100682040 - 0x100680720 类对象 - 0x7fff8897a008 - 0x7fff8897a008 - 0x7fff8897a008 - 0x7fff8897a008 - 0x7fff8897a008 - 0x7fff8897a008
objCls1 - objCls6都是NSObject的类对象,它们是同一个对象;
元类(meta-class)对象
每个类在内存中有且只有一个meta-class对象;元类对象的存储信息:
- isa指针
- superclass指针
- 类的类方法信息
- ...
Class metaCls1 = object_getClass(objCls1); Class metaCls2 = object_getClass(objCls2); Class metaCls3 = objc_getMetaClass("NSObject"); NSLog(@"元类对象 - %p - %p - %p", metaCls1, metaCls2, metaCls3); NSLog(@"%d", class_isMetaClass(metaCls1));
运行结果
元类对象 - 0x7fff88979fe0 - 0x7fff88979fe0 - 0x7fff88979fe0 1
isa指针
通过之前OC的底层实现,我们知道了NSObject的底层编译是NSObject_IMPL结构体,结构体内部是一个Class类型的isa,而Class类型为objc_class结构体指针,故isa也是一个指针;
@interface Person : NSObject - (void)instanceMethod; + (void)classMethod; @end
实例对象的isa指向类对象(class)
当我们调用Person中instanceMethod方法时,通过实例对象的isa找到class,最后找到instanceMethod方法进行调用;
类对象的isa指向元类对象(meta-class)
当我们调用Person中classMethod时,通过class的isa找到元类对象,最后找到classMethod方法进行调用;
类对象的superclass指针
@interface Person : NSObject - (void)instanceMethod; @end @interface Student : Person @end
当我们调用Student的instanceMethod方法时,先通过Student的isa找到class对象,然后通过superclass找到Person的class,最后找到instanceMethod实例方法进行调用;元类对象的superclass指针
@interface Person : NSObject + (void)classMethod; @end @interface Student : Person @end
当我们调用Student的classMethod方法时,先通过Student的isa找到meta-class对象,然后通过superclass找到Person的meta-class,最后找到classMethod类方法进行调用;
isa指针 & supercalss指针
通过下方这张图,我们来分析一下整个查找流程
虚线代表isa指针,实现代表superclass指针;
- instance的isa指向class;
- class的isa指向meta-class;
- meta-class的isa指向基类的meta-class;
- class的superclass指向父类的class,如果没有父类,superclass指针为nil;
- meta-class的superclass指向父类的meta-class;
- 基类的meta-class的superclass指向基类的class;
- instance调用对象方法的轨迹:通过isa找到class,方法不存在,就通过superclass找父类class;
- 调用类方法的轨迹:通过isa找meta-class,方法不存在,就通过superclass找父类;
调用方法的时候,如果寻找上层依旧找不到,会报一个很经典的错误unrecognized selector sent to instance
;
此处还有一个注意点,注意看图中warn那条线,当基类的meta-class对象查找类方法如果不存在的话,会向基类的类对象里面去找,具体意思是什么?可以参考下方的示例:
@interface Person : NSObject + (void)test; @end @implementation Person @end @interface NSObject (Extention) @end @implementation NSObject (Extention) - (void)test { NSLog(@"NSObject - (void)test"); } @end
调用test方法
[Person test];
运行结果
NSObject - (void)test
当我们调用test类方法的时候,发现在元类对象meta-class以及元类基类对象meta-class中都无法查找到,这个时候就会去类的基类对象class里面去找,执行到了类的基类对象class里面的实例方法,故调用了NSObject里面的test实例方法;