我们先来看一个问题,下面的代码会输出什么?
@implementation Son : Father
- (id)init {
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
答案:都输出 Son。
Son
Son
如果不了解isa
的话,可能对这个结果会有点疑惑,+class
、-class
方法里到底做了什么呢?
isa 指向
我们来看下源码:
//rumtime.h
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
//.....
}
//NSObject.mm
@implementation NSObject
+ (Class)class {
return self ;
}
- (Class)class {
return object_getClass(self);
}
Class object_getClass(id obj) {
if (obj) return obj->getIsa();
else return Nil;
}
@end
类的class
方法返回了类对象自身,对象的class
方法返回了isa
指针。那么isa
到底指向什么?
class isa
我们先来看看class
的isa
指向的是什么,我们从class
的创建函数里找到一些关键信息:
//objc-runtime-new.mm
Class objc_allocateClassPair(Class superclass, const char *name,
size_t extraBytes) {
Class cls, meta;
rwlock_writer_t lock(runtimeLock);
// Fail if the class name is in use.
// Fail if the superclass isn't kosher.
if (getClass(name) || !verifySuperclass(superclass, true/*rootOK*/)) {
return nil;
}
// Allocate new classes.
//创建 cls、meta 两个class
cls = alloc_class_for_subclass(superclass, extraBytes);
meta = alloc_class_for_subclass(superclass, extraBytes);
// fixme mangle the name if it looks swift-y?
//初始化cls、meta,并设置关联。
objc_initializeClassPair_internal(superclass, name, cls, meta);
return cls;
}
objc_allocateClassPair
提供了创建class
的功能,方法内部生成了cls
和meta
两个class
,并调用objc_initializeClassPair_internal
进行初始化。我们继续看函数内部。
static const uint8_t UnsetLayout = 0;
static void objc_initializeClassPair_internal(Class superclass, const char *name, Class cls, Class meta) {
runtimeLock.assertWriting();
class_ro_t *cls_ro_w, *meta_ro_w;
cls->cache.initializeToEmpty();
meta->cache.initializeToEmpty();
//省略部分代码...
// Set basic info
cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
cls->data()->version = 0;
meta->data()->version = 7;
cls_ro_w->flags = 0;
meta_ro_w->flags = RO_META;
//省略部分代码...
cls_ro_w->name = strdup(name);
meta_ro_w->name = strdup(name);
cls_ro_w->ivarLayout = &UnsetLayout;
cls_ro_w->weakIvarLayout = &UnsetLayout;
// Connect to superclasses and metaclasses
cls->initClassIsa(meta);
if (superclass) {
//有父类
meta->initClassIsa(superclass->ISA()->ISA());
cls->superclass = superclass;
meta->superclass = superclass->ISA();
addSubclass(superclass, cls);
addSubclass(superclass->ISA(), meta);
} else {
//没有父类
meta->initClassIsa(meta);
cls->superclass = Nil;
meta->superclass = cls;
addSubclass(cls, meta);
}
}
内容比较多,大致来看,objc_initializeClassPair_internal
做了5个事情,
-
初始化
cls
和meta
的name
、data
、version
等等属性。 -
连接了
cls
和meta
,cls->isa
指向meta
。 -
设置
meta->isa
。- 若
cls
无superclass
(NSObject
),那么meta->isa
指向meta
自身。 - 若
cls
有superclass
,那么meta->isa
指向superclass->isa->isa
,其实也就是NSObject meta
。
- 若
-
设置
meta->superclass
。- 若
cls
无superclass
(NSObject
),那么meta->superclass
指向cls
。 - 若
cls
有superclass
(NSObject
),那么meta->superclass
指向superclass->isa
。
- 若
-
设置
cls->superclass
。
这样可能有点晕,我们来举个例子,假如我们现在有Grandson
、Son
、Father
3个Class
,前者依次继承后者,我们来分析一下各自的isa
、superclass
是如何关联的。
-
初始化
class
,生成对应的cls
和meta
两个class,并初始化name
、data
、version
等等属性。 -
调用
cls->initClassIsa(meta)
,关联cls、meta
。Father class->isa
指向Father meta
。Son class->isa
指向Son meta
。Grandson class->isa
指向Grandson meta
。
-
调用
meta->initClassIsa(superclass->ISA()->ISA())
,设置meta isa
。Father meta->isa
指向NSObject class->isa->isa
,也就是NSObject meta->isa
,即NSObject meta
自己(NSObject没有superclass)。Son meta->isa
指向Father class->isa->isa
,也就是Father meta->isa
,即NSObject meta
。Grandson meta->isa
指向Son class->isa->isa
,也就是Son meta->isa
,也就是步骤4,最后也是NSObject meta
。
-
调用
meta->superclass = superclass->ISA()
,设置meta superclass
。NSObject meta->superclass
指向NSObject
。Father meta->superclass
指向NSObject isa
,即NSObject meta
。Son meta->superclass
指向Father isa
,即Father meta
。Grandson meta->superclass
指向Son isa
,即Son meta
。
object isa
弄清楚class
、meta
之间的关系后,我们再来看看object
里的isa
是如何设置的。
首先我们来看下alloc init
的底层实现。
//NSObject.h
@interface NSObject <NSObject>
+ (id)alloc {
return _objc_rootAlloc(self);
}
@end
//NSObject.mm
id _objc_rootAlloc(Class cls) {
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false) {
if (checkNil && !cls) return nil;
#if __OBJC2__
if (! cls->ISA()->hasCustomAWZ()) {
if (cls->canAllocFast()) {
// obj->isa = cls,即对象的isa指向class。
obj->initInstanceIsa(cls, dtor);
return obj;
}
else {
// Has ctor or raw isa or something. Use the slower path.
id obj = class_createInstance(cls, 0);
if (!obj) return callBadAllocHandler(cls);
return obj;
}
}
#endif
if (allocWithZone) return [cls allocWithZone:nil];
return [cls alloc];
}
id class_createInstance(Class cls, size_t extraBytes) {
return _class_createInstanceFromZone(cls, extraBytes, nil);
}
static __attribute__((always_inline)) id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil) {
if (!cls) return nil;
//省略部分代码...
id obj;
if (!UseGC && !zone && fast) {
obj = (id)calloc(1, size);
if (!obj) return nil;
// obj->isa = cls,即对象的isa指向class。
obj->initInstanceIsa(cls, hasCxxDtor);
}
else {
//省略部分代码...
if (zone) {
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}
// obj->isa = cls,即对象的isa指向class。
obj->initIsa(cls);
}
//省略部分代码...
return obj;
}
这里我省略了部分无关代码,方法调用层级还是有点多,但是不难发现,最后都是调用了initIsa
或者initInstanceIsa
,把obj->isa
指向了cls
,所以得到:
obj->isa = cls
class & meta
到这里,isa
指向关系我们大概清楚了,但是class
、meta
有什么区别吗?
class
类对象,包含了isa
、superclass
、变量、协议、实例方法等等成员。meta
元类对象,包含了isa
、superclass
、静态方法列表等成员。
通过代码来验证一下他们的结构:
//首页声明 Father class
@interface Father : Father
@property (nonatomic, strong) NSString *name;
@end
@implementation Father
static NSString *nickname = @"";
- (void)eta {}
+ (void)clothe {}
@end
///打印变量
- (void)printIvars:(Class )cls {
unsigned int count = 0;
Ivar *members = class_copyIvarList(cls, &count);
for(int i = 0; i < count; i++) {
Ivar ivar = members[i];
const char *memberName = ivar_getName(ivar);
NSLog(@"%@,%p,%@", cls, cls, [NSString stringWithCString:memberName encoding:NSUTF8StringEncoding]);
}
free(members);
}
///打印方法
- (void)printMethods:(Class )cls {
unsigned int methodCount;
Method *methodList = class_copyMethodList(cls, &methodCount);
unsigned int i = 0;
for (; i < methodCount; i++) {
NSLog(@"%@,%p,%@", cls, cls, [NSString stringWithCString:sel_getName(method_getName(methodList[i])) encoding:NSUTF8StringEncoding]);
}
free(methodList);
}
//打印class、meta的成员
- (void)test {
Father *obj1 = [[Father alloc] init];
NSLog(@"==");
[self printIvars:obj1.class];
[self printMethods:obj1.class];
NSLog(@"==");
[self printIvars:object_getClass(obj1.class)];
[self printMethods:object_getClass(obj1.class)];
}
输出日志:
==
Father,0x10673c4d8,_name
Father,0x10673c4d8,name
Father,0x10673c4d8,.cxx_destruct
Father,0x10673c4d8,setName:
Father,0x10673c4d8,eta
==
Father,0x10673c4b0,clothe
很明显的看到,class
类对象里包含了实例方法、变量等等成员,meta
只包含了静态方法。
结论
现在我们对isa
指针比较清楚了,这里再做一个总结:
instance->isa
=class
class->isa
=meta
meta->isa
=superclass->isa->isa
=NSObject meta
NSObject meta->isa
=NSObject meta
meta->superclass
=superclass->isa
NSObject meta->superclass
=NSObject class
class->superclass
=superclass
NSObject class->superclass
=nil
再看这张图片就很容易理解了。
验证
最后我们做一个简单的testing,来验证一下上面的结论。
//声明Son、Father
@interface Father : NSObject
@end
@implementation Father
@end
@interface Son : Father
@end
@implementation Son
@end
// 测试
- (void)test {
Son *obj1 = [[Son alloc] init];
//对象的isa
NSLog(@"%@,%p,%p,%d,%d", obj1.class, obj1.class, Son.class, obj1.class == Son.class, class_isMetaClass(obj1.class));
//class的isa = meta
Class class1Isa = object_getClass(obj1.class);
NSLog(@"%@,%p,%d", class1Isa, class1Isa, class_isMetaClass(class1Isa));
//class的isa的isa = meta的isa = NSObject meta
Class meta1Isa = object_getClass(class1Isa);
NSLog(@"%@,%p,%d", meta1Isa, meta1Isa, class_isMetaClass(meta1Isa));
Father *obj2 = [[Father alloc] init];
//对象的isa
NSLog(@"%@,%p,%p,%d,%d", obj2.class, obj2.class, Father.class, obj2.class == Father.class, class_isMetaClass(obj1.class));
//class的isa = meta
Class class2Isa = object_getClass(obj2.class);
NSLog(@"%@,%p,%d", class2Isa, class2Isa, class_isMetaClass(class2Isa));
//class的isa的isa = meta的isa = NSObject meta
Class meta2Isa = object_getClass(class2Isa);
NSLog(@"%@,%p,%d", meta2Isa, meta2Isa, class_isMetaClass(meta2Isa));
}
运行后,输出以下日志。
//obj->isa = class
Son,0x1052a8318,0x1052a8318,1,0
//class->isa = meta
Son,0x1052a82f0,1
//meta->isa = NSObject meta
NSObject,0x7fff89d23d18,1
//同上
Father,0x1052a82c8,0x1052a82c8,1,0
Father,0x1052a82a0,1
NSObject,0x7fff89d23d18,1
可以很清楚的看到:
obj1->isa
=Son class
,即0x10a079310
,且不是meta
。class->isa
=meta
,即0x1052a82f0
meta->isa
=NSObject meta
=Father meta->isa
,即0x7fff89d23d18
。