- instance 对象的 isa 指针指向 class, 当调用对象方法时, isa 找到 class, 然后找到相应方法进行调用
- class 对象的 isa 指针指向 meta-class, 当调用类方法时, isa 找到 meta-class, 然后找到相应方法进行调用
- meta-class 对象的 isa 指针指向基类的 meta-class, 基类的指向自己
instance 对象调用流程: instance(subclass) 中的 isa 去 subclass 中找方法, 如果没找到就用
superclass
指针找到 subclass 的父类 superclass, 如果还没有就继续递进到 rootclass 中查找, 还是没有就在运行时报错误 crash "unrecognized selector sent to instance"
class 对象调用和 instance 对象一样, 只不过是去 meta-class 中查找类方法, 最后找不到, 就会从 root-meta-class 找, 如果还是找不到就去 rootclass 找对象方法, 还是没有就在运行时报错误 crash "unrecognized selector sent to class"
以下是对 isa
指针指向做的代码分析, 断点看下 isa
的地址
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
// 对象的 isa 指针指向哪里?
void about_isa(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
about_isa();
}
return 0;
}
@interface Test : NSObject
@end
@implementation Test
@end
void about_isa() {
// instance 对象的 isa 指针指向 class, 当调用对象方法时, isa 找到 class, 然后找到相应方法进行调用
// class 对象的 isa 指针指向 meta-class, 当调用类方法时, isa 找到 meta-class, 然后找到相应方法进行调用
// meta-class 对象的 isa 指针指向基类的 meta-class, 基类的指向自己
// instance 对象调用流程: instance(subclass) 中的 isa 去 subclass 中找方法, 如果没找到就用 `superclass` 指针找到 subclass 的父类 superclass, 如果还没有就继续递进到 rootclass 中查找, 还是没有就在运行时报错误 crash "unrecognized selector sent to instance"
// class 对象调用和 instance 对象一样, 只不过是去 meta-class 中查找类方法, 最后找不到, 就会从 root-meta-class 找, 如果还是找不到就去 rootclass 找**对象方法**, 还是没有就在运行时报错误 crash "unrecognized selector sent to class"
/** lldb 调试一下 test 的 isa 指针地址
* (lldb) p/x (long)test->isa
* (long) $1 = 0x001d800100002119
*
* 与下面的 testClass 作对比发现 isa 的指针并不是指向类, 其实在 64bits 系统以后 isa 做了调整, 看源码搜索 "ISA_MASK" 就能找到一个宏定义, 将 isa & ISA_MASK 进行位运算才能得到实际的类, 由于我用的是 MacOS 所以对应的 ISA_MASK 为 0x00007ffffffffff8ULL , iOS 为 0x0000000ffffffff8ULL, meta-class 同理可证
*
* (lldb) p/x 0x00007ffffffffff8ULL & 0x001d800100002119
* (unsigned long long) $7 = 0x0000000100002118
*/
Test *test = Test.new;
/** lldb 调试一下 testClass 的指针地址
* (lldb) p/x testClass
* (Class) $4 = 0x0000000100002118 Test
*
* lldb 调试一下, 由于 Class 类型没有暴露 isa 指针, 我需要做一个结构体强转, 这样得到 isa 的地址
* (lldb) p/x testClass2->isa
* (Class) $0 = 0x00000001000020f0
*/
struct object_class {
Class isa;
};
Class testClass = test.class;
struct object_class *testClass2 = (__bridge struct object_class *)(testClass);
/**
* (lldb) p/x testMetaClass
* (Class) $1 = 0x00000001000020f0
* (lldb) p/x 0x00000001000020f0 & 0x00007ffffffffff8ULL
* (unsigned long long) $2 = 0x00000001000020f0
*/
Class testMetaClass = object_getClass(testClass);
NSLog(@"%p - %p - %p - %p", test, testClass, testClass2, testMetaClass);
}
网友评论