本文objc源码是objc4-838,不同源码苹果官方可能会有变化。
前言
本文主要探究类的结构并分析类方法及ivar
一、isa指向
首先自定义一个类SLPerson。
@interface SLPerson : NSObject
{
NSString * subject;
}
@property(copy,nonatomic)NSString * name;
@property(copy,nonatomic)NSString * hobby;
-(void)sayNB;
+(void)say666;
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
SLPerson * p = [[SLPerson alloc];
NSObject * obj = [NSObject alloc];
}
return 0;
}
通过lldb来查看内存地址,分析如下图
SLPerson实例对象p的isa指向:p——>SLPerson类对象——>SLPerson元类对象——>NSObject元类对象——>NSObject元类对象(指向自身)。
二、superclass继承关系总结
1.实例对象之间不存在继承关系,类或元类才有继承关系。
2.NSObject元类继承NSObjct类,NSObjct类继承自nil
三、isa指向图和superclass图
四、类结构分析和探索
1.objc_object&objc_class源码
typedef struct objc_class *Class;
typedef struct objc_object *id;
struct objc_class : objc_object {
.....
// Class ISA; //8字节 从objc_object继承而来
Class superclass; //8字节
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
........
class_rw_t *data() const {
return bits.data();
}
}
类的信息在class_data_bits_t中,struct objc_class中成员内存是连续的,所以通过类地址加上特定指针内存平移来查看源码。isa和superclass占8字节,下面来分析cache_t的大小。
cache_t的大小
首先看源码,由于static变量不占用此结构体存储空间,所以我们分析关键代码,如下:
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask; //8
union {
struct {
explicit_atomic<mask_t> _maybeMask; //4
#if __LP64__
uint16_t _flags; //2
#endif
uint16_t _occupied; //2
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache; //8
};
......此处省略好多代码
}
可以得出共用体union的大小是8字节,加上_bucketsAndMaybeMask的8字节,得到cache_t大小是16字节。那么我们就可以通过类的首地址加上8+8+16=32字节(0x20)偏移获得class_data_bits_t bits首地址。
2.class_data_bits_t
a. 获取class_data_bits_t bits首地址
(lldb) x/4gx SLPerson.class
0x100008388: 0x0000000100008360 0x000000010080e140
0x100008398: 0x0000000100806230 0x0000802800000000
(lldb) p (class_data_bits_t *)(0x100008388+0x20)
(class_data_bits_t *) $1 = 0x00000001000083a8
b.获取class_rw_t
类型的 data
地址
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000100f047e0
(lldb) p *$2
(class_rw_t) $3 = {
flags = 2148007936
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4295000488
}
}
firstSubclass = nil
nextSiblingClass = 0x00007ff8480b19c8
}
c.查看属性列表properties
(lldb) p $3.properties()
(const property_array_t) $4 = {
list_array_tt<property_t, property_list_t, RawPtr> = {
= {
list = {
ptr = 0x0000000100008180
}
arrayAndFlag = 4295000448
}
}
}
(lldb) p $4.list
(const RawPtr<property_list_t>) $5 = {
ptr = 0x0000000100008180
}
(lldb) p $5.ptr
(property_list_t *const) $6 = 0x0000000100008180
(lldb) p *$6
(property_list_t) $7 = {
entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $7.get(0)
(property_t) $8 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $7.get(1)
(property_t) $9 = (name = "hobby", attributes = "T@\"NSString\",C,N,V_hobby")
总结:调用properties可以找到属性name,hobby,但是没找到成员变量subject。
d.查看methods()
(lldb) p $10.list.ptr
(method_list_t *const) $11 = 0x0000000100008098
(lldb) p *$11
(method_list_t) $12 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 5)
}
(lldb) p $12.get(0).big()
(method_t::big) $14 = {
name = "sayNB"
types = 0x0000000100003ede "v16@0:8"
imp = 0x0000000100003be0 (KCObjcBuild`-[SLPerson sayNB])
}
(lldb) p $12.get(1).big()
(method_t::big) $15 = {
name = "hobby"
types = 0x0000000100003ee6 "@16@0:8"
imp = 0x0000000100003c40 (KCObjcBuild`-[SLPerson hobby])
}
(lldb) p $12.get(2).big()
(method_t::big) $16 = {
name = "setHobby:"
types = 0x0000000100003eee "v24@0:8@16"
imp = 0x0000000100003c60 (KCObjcBuild`-[SLPerson setHobby:])
}
(lldb) p $12.get(3).big()
(method_t::big) $17 = {
name = "name"
types = 0x0000000100003ee6 "@16@0:8"
imp = 0x0000000100003bf0 (KCObjcBuild`-[SLPerson name])
}
(lldb) p $12.get(4).big()
(method_t::big) $18 = {
name = "setName:"
types = 0x0000000100003eee "v24@0:8@16"
imp = 0x0000000100003c10 (KCObjcBuild`-[SLPerson setName:])
}
总结:调用methods()
打印出的方法没有类方法,只有实例方法。
3.查看ivars
(lldb) x/4gx SLPerson.class
0x100008388: 0x0000000100008360 0x000000010080e140
0x100008398: 0x0000000100806230 0x0000802800000000
(lldb) p (class_data_bits_t *)(0x100008388+0x20)
(class_data_bits_t *) $1 = 0x00000001000083a8
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000100f12330
(lldb) p *$2
(class_rw_t) $3 = {
flags = 2148007936
witness = 0
ro_or_rw_ext = {
std::__1::atomic<unsigned long> = {
Value = 4295000488
}
}
firstSubclass = nil
nextSiblingClass = 0x00007ff8480b19c8
}
(lldb) p $3.ro()
(const class_ro_t *) $4 = 0x00000001000081a8
(lldb) p *$4
(const class_ro_t) $5 = {
flags = 0
instanceStart = 8
instanceSize = 32
reserved = 0
= {
ivarLayout = 0x0000000000000000
nonMetaclass = nil
}
name = {
std::__1::atomic<const char *> = "SLPerson" {
Value = 0x0000000100003e08 "SLPerson"
}
}
baseMethods = {
ptr = 0x0000000100008098
}
baseProtocols = nil
ivars = 0x0000000100008118
weakIvarLayout = 0x0000000000000000
baseProperties = 0x0000000100008180
_swiftMetadataInitializer_NEVER_USE = {}
}
(lldb) p $5.ivars
(const ivar_list_t *const) $6 = 0x0000000100008118
(lldb) p *$6
(const ivar_list_t) $7 = {
entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 3)
}
(lldb) p $7.get(0)
(ivar_t) $8 = {
offset = 0x0000000100008348
name = 0x0000000100003e45 "subject"
type = 0x0000000100003ef9 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7.get(1)
(ivar_t) $9 = {
offset = 0x0000000100008350
name = 0x0000000100003e4d "_name"
type = 0x0000000100003ef9 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $7.get(2)
(ivar_t) $10 = {
offset = 0x0000000100008358
name = 0x0000000100003e53 "_hobby"
type = 0x0000000100003ef9 "@\"NSString\""
alignment_raw = 3
size = 8
}
总结:ivar_list_t中,属性(name、hobby)会生成下划线,成员变量(subject)没有下划线。
4.类方法
总结:类方法存在元类对象中。
五、isKindOfClass和isMemberOfClass
1.isKindOfClass:
源码如下:
+ (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;
}
测试代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; //
BOOL re2 = [(id)[SLPerson class] isKindOfClass:[SLPerson class]]; //
BOOL re3 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //
BOOL re4 = [(id)[SLPerson alloc] isKindOfClass:[SLPerson class]]; //
NSLog(@"\n re1:%hhd re2:%hhd re3:%hhd re4:%hhd",re1,re2,re3,re4);
}
return 0;
}
结果:
- re1——1、tcls = self->ISA()是NSObject元类(即根元类),cls为[NSObject class]是类;2、tcls取tcls->superclass,根元类的父类是NSObject类,等于cls,返回YES。
- re2——1、tcls = self->ISA()是SLPerson元类,cls为[SLPerson class]是类;2、tcls取tcls->superclass,SLPerson元类的父类是根元类,不等于cls;3、根元类的父类是NSObject类,不等于cls;4、NSObject类的父类是nil,for循环终止,返回NO。
- re3——tcls = [self class]是NSObject类,等于cls,返回YES。
- re4——tcls = [self class]是SLPerson类,等于cls,返回YES。
2.isMemberOfClass
源码如下:
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
测试代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
BOOL re5 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //
BOOL re6 = [(id)[SLPerson class] isMemberOfClass:[SLPerson class]]; //
BOOL re7 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //
BOOL re8 = [(id)[SLPerson alloc] isMemberOfClass:[SLPerson class]]; //
NSLog(@"\n re5:%hhd re6:%hhd re7:%hhd re8:%hhd",re5,re6,re7,re8);
}
return 0;
}
结果
- re5——
self->ISA()
是根元类,cls是NSObject类,不相等返回NO。
re6——self->ISA()
是SLPerson元类,cls是SLPerson类,不相等返回NO。- re7——
self->ISA()是NSObject类,等于cls,返回YES。
- re8——
self->ISA()是
SLPerson类,等于cls,返回YES。