isa指针
instance
的 isa
指向 class
。
class
的 isa
指向 meta-class
。
meta-class
的 isa
指向基类的 meta-class
。
superclass指针
class
的 superclass
指向父类的 class
,没有父类(NSObject
就没父类)则为 nil
。
meta-class
的 superclass
指向父类的 meta-class
。基类的 meta-class
的 superclass
指向基类的 class
。
isa和superclass指向图示
对象方法调用
当调用 对象方法
时,通过 instance
的 isa
指针找到 class
,最后找到 对象方法
的实现进行调用。
如果在 class
中未找到 对象方法
的实现,则去 class
的 superclass
中查找,以此类推。
// 伪代码
objc_msgSend(实例对象, @selector(对象方法));
类方法调用
当调用 类方法
时,通过 class
的 isa
指针找到 meta-class
,最后找到 类方法
的实现进行调用。
如果在 meta-class
中未找到 类方法
的实现,则去 meta-class
的 superclass
中查找,以此类推。
// 伪代码
objc_msgSend(类对象, @selector(类方法));
类方法调用特殊情况
基类中不存在类方法,但存在同名对象方法:
@interface JFPerson : NSObject
@end
@implementation JFPerson
@end
@interface NSObject (Test)
+ (void)test;
@end
@implementation NSObject (Test)
- (void)test
{
NSLog(@"-[NSObject test]: %p", self);
}
@end
调用类方法,没有报错:
NSLog(@"[JFPerson class]: %p", [JFPerson class]);
NSLog(@"[NSObject class]: %p", [NSObject class]);
[JFPerson test];
[NSObject test];
最终输出:
[JFPerson class]: 0x100008110
[NSObject class]: 0x20c402330
-[NSObject test]: 0x100008110
-[NSObject test]: 0x20c402330
这是因为在基类的 meta-class
中没有查找到对应的 类方法
,就会通过基类的 meta-class
的 superclass
指针,去基类的 class
中查找同名 对象方法
。
验证isa指向
NSObject *p1 = [[NSObject alloc] init];
Class pClass = [NSObject class];
通过 lldb
指令打印 isa
指向的地址和类对象地址值:
(lldb) p/x p1->isa
(Class) $0 = 0x010000020c402331 NSObject
(lldb) p/x pClass
(Class) $1 = 0x000000020c402330 NSObject
可以发现 isa
指向的并不直接是 class
。
这是因为在 32
位操作系统时期,实例对象的 isa
指针才是直接指向类对象的。
但是从 64
位开始,isa
需要进行一次位运算,才能计算出真实地址。
计算地址值
在 objc4
的 isa.h
源码中可以拿到 ISA_MASK
的宏定义:
#if __arm64__
#if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
#define ISA_MASK 0x007ffffffffffff8ULL
#else
#define ISA_MASK 0x0000000ffffffff8ULL
#endif
#elif __x86_64__
#define ISA_MASK 0x00007ffffffffff8ULL
#endif
最终通过位运算,结论正确:
0x010000020c402331 & ISA_MASK == 0x000000020c402330;
class
和 meta-class
中的 isa
也是相同的计算方式。
了解类对象的结构
在 objc4
的 objc-runtime-new.h
源码中:
typedef struct objc_class *Class;
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; // isa指针
};
struct objc_class : objc_object {
Class superclass;
cache_t cache; // 方法缓存
class_data_bits_t bits; // 用于获取具体的类信息
// 存储的数据
class_rw_t *data() const {
return bits.data();
}
};
struct class_rw_t {
// 多个函数操作class_rw_ext_t结构体
};
struct class_rw_ext_t {
DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)
class_ro_t_authed_ptr<const class_ro_t> ro;
method_array_t methods; // 方法列表
property_array_t properties; // 属性列表
protocol_array_t protocols; // 协议列表
char *demangledName;
uint32_t version;
};
isKindOfClass和isMemberOfClass
BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [[Person class] isKindOfClass:[Person class]];
BOOL res4 = [[Person class] isMemberOfClass:[Person class]];
NSLog(@"%d %d %d %d", res1, res2, res3, res4); // 1 0 0 0
在 objc4
的 NSObject.mm
源码中可以获取到下面代码:
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
可以看出,如果是类方法,则是用自身对象的 isa
和传入对象比较,也就是对应的元类对象
和类对象
进行比较,结果显而易见。