目标的分类
Object- C
中一切目标能够分为3类,实例目标,类目标,元类目标。其间我们开发者常用的承继自NSObject
都归于实例目标,实例目标经过isa
指针指向的是类目标。类目标经过isa
指向的是元类目标。类目标和元类目标拥有相同的结构,都是来自objc_class
。
objc_class结构
在objc4源码中查找objc_class
能够找到其结构
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
}
其间isa指针式其承继自objc_object
的。本文主要解说类结构中的isa
、superclass
、bits
,cache
的内容单放一篇。
isa
在之前的内容里边现已讲过,主要是指向类目标或者元类目标的。
superclass
是体现出承继联系的。
cache
是办法缓存。
bits
是类的其他信息,例如成员变量,办法列表,协议,特点。
留意:元类目标结构也是如此,但元类目标里边没有成员变量,协议,特点这些内容。
isa指向图
相信做iOS开发都必须掌握的一个图。
这儿对isa
指向做一个简略的总结
实例目标的
isa
指针指向对应的类目标,类目标的isa
指针指向对应的元类目标,元类目标的isa
指向基类的元类目标(根元类)。
能够简略的用lldb
调试来验证一下。
- (void)test {
//
NSObject *objc = [[NSObject alloc] init];
//isa指向的就是类目标
Class objcClass1 = [NSObject class];
Class objcMetaClass = object_getClass([NSObject class]);
}
先获取objc
的isa
指针的值,然后用这个值与运算ISA_MASK
,得到的值,正好是类目标的地址。
然后用相同的办法获取类目标的值,和ISA_MASK
与运算得到元类目标的地址。
能够持续这样再操作一轮,得到的还是元类目标的地址。这是由于该类是NSObject
,NSObject
元类目标的isa
是指向自己的(图中右上交的循环箭头)。
这儿由于0x00000001d64226c0
的高9位和低3位都是0所以没有做与运算,结果其实是相同的。
留意ISA_MASK
的使用需要留意环境,我这儿是M1的模拟器。
superClass指向
superClass
的指向也在上面那个经典的图中。这儿要留意superclass
是objc_class
才有的,所以实例目标是没有的。类目标的superclass
指向父类目标,元类目标的superclass
指向父类的元类目标,根元类目标的superclass
指针指向 根类目标。根类目标的superclass
是nil
。
留意:根元类目标的superclass
指针指向 根类目标,这个是有一个面试题的。
请听题:
@interface NSObject (Interview)
+ (void)foo;
@end
@implementation NSObject (Interview)
//能经过这个调用的原因是,NSObject的基元类的supclass为NSobject的元类
- (void)foo {
NSLog(@"IMP: -[NSObject foo]");
}
@end
- (void)test {
[NSObject foo];
}
上面的代码能执行成功么?这题要结合objc_msgSend
一起看,调查的点就是根元类目标的superclass
指针指向根类目标。
bits
类的结构中还有一个bits
,里边也存了很多信息,我们先看bits
的数据结构 class_data_bits_t
。
struct class_data_bits_t {
friend objc_class;
// Values are the FAST_ flags above.
uintptr_t bits;
public:
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
// Get the class's ro data, even in the presence of concurrent realization.
// fixme this isn't really safe without a compiler barrier at least
// and probably a memory barrier when realizeClass changes the data field
const class_ro_t *safe_ro() const {
class_rw_t *maybe_rw = data();
if (maybe_rw->flags & RW_REALIZED) {
// maybe_rw is rw
return maybe_rw->ro();
} else {
// maybe_rw is actually ro
return (class_ro_t *)maybe_rw;
}
}
}
其实最最重要的是其间的2个办法。data
和 safe_ro
,两个办法分别返回class_rw_t
和class_ro_t
。
这儿ro_t
的获取也是经过data
办法获取的,一切能够理解为ro_t
也在rw_t
之中。
class_rw_t
持续来看class_rw_t
的数据结构。
在rw_t
中能够 看到有这3个办法,经过这三个办法分别能获取到类的办法、特点、协议。
class_ro_t
再看class_ro_t
的数据结构。
能够看到有办法、特点、协议和成员变量。但办法、特点、协议的命名都是base
注册的。