类的分析
对象的isa指向的是类,万物皆对象,类也是个对象,类里面也有isa,那么类isa是指向哪个类呢?这个类就是苹果定义的元类
元类(metaClass)
存在即合理,元类存在的意义在哪里?
int main(int argc, char * argv[]) {
@autoreleasepool {
Class class1 = [SWPerson class];
Class class2 = [SWPerson alloc].class;
Class class3 = object_getClass([SWPerson alloc]);
Class class4 = [SWPerson alloc].class;
NSLog(@"\n-%p-\n-%p-\n-%p-\n-%p-",class1,class2,class3,class4);
}
return
}
结果:
-0x100009510-
-0x100009510-
-0x100009510-
-0x100009510-
- 类对象的地址都是一样的,内存中每一个类只有一块内存,和普通的对象有明显的区别
用来获取类信息的掩码,将isa的地址&、ISA_MASK,可以解析得到类的信息,ISA_MASK是系统定义的,不同架构不同,我在objc4源码内拿到的 x86_64:define ISA_MASK 0x00007ffffffffff8ULL arm64:define ISA_MASK 0x0000000ffffffff8ULL arm64(simulators):define ISA_MASK 0x007ffffffffffff8ULL
- p/x SWPerson.class 得到类对象内存地址0x00000001000080e8,x/4gx格式化输出类对象的内存地址
- p/x 0x00000001000080c0 & 0x00007ffffffffff8将类对象的首地址(isa指针地址)0x00000001000080c0和ISA_MASK做与操作,得到了一个新的内存地址0x00000001000080c0
- po 0x00000001000080c0 打印这个地址数据,得到了SWPerson 0x00000001000080e8 和 0x00000001000080c0 是两个不同的地址,0x00000001000080e8 是类地址,而 0x00000001000080c0 地址对应的类就叫元类
小结
- 元类是系统编译器自动创建的,和用户没关系
- 实例对象的isa指向类,类对象的isa指向元类
- 类名和它关联类即元类名是一样的(只有关联元类才有类名)
isa走位图分析
Apple 官方 isa走位和继承图
- 实例对象的isa --> 类对象
- 类对象的isa--> 元类
- 元类isa--> 根元类
- 根元类的isa--> 根元类(指向自己)
类 元类 根元类继承图
int main(int argc, char * argv[]) {
@autoreleasepool {
Class tMetaClass = object_getClass(SWTeacher.class); //SWTeacher 的元类
Class tMetaSuperClass = class_getSuperclass(tMetaClass);//SWTeacher 的元类的父类
Class pMetaClass = object_getClass(SWPerson.class); //SWPerson 的元类
Class pMeatSuperClass = class_getSuperclass(pMetaClass);//SWPerson 的元类的父类
Class nMetaClass = object_getClass(NSObject.class); //NSObject的元类
Class nSuperClass = class_getSuperclass(NSObject.class);//NSObject的父类
Class nMetaSuperClass = class_getSuperclass(nMetaClass);//NSObject的元类的父类
NSLog(@"SWTeacher-%p",SWTeacher.class);
NSLog(@"SWPerson-%p",SWPerson.class);
NSLog(@"NSObject-%p",NSObject.class);
NSLog(@"%@ - %p - %@ - %p",tMetaClass,tMetaClass,tMetaSuperClass,tMetaSuperClass);
NSLog(@"%@ - %p - %@ - %p",pMetaClass,pMetaClass,pMeatSuperClass,pMeatSuperClass);
NSLog(@"%@ - %p - %@ - %p",nMetaClass,nMetaClass,nMetaSuperClass,nMetaSuperClass);
}
return
}
SWTeacher-0x100009618
SWPerson-0x100009528
NSObject-0x7fff8deb3118
SWTeacher - 0x1000095f0 - SWPerson - 0x100009500
SWPerson - 0x100009500 - NSObject - 0x7fff8deb30f0
NSObject - 0x7fff8deb30f0 - NSObject - 0x7fff8deb3118
- - (null)
NSObject的父类打印的结果是nil。SWTeacher
的元类的父类是 SWPerson
的元类(SWPerson
的元类的地址和SWPerson
类的地址不一样)。SWPerson
的元类的父类是 NSObject
的元类,NSObject
的元类的父类是NSObject
(和NSObject
类的地址一样)
SWTeacher
继承SWPerson
,SWPerson
继承NSObject
,NSObject
的父类是nil
SWTeacher
元类继承SWPerson
元类,SWPerson
继承根元类
,根元类
继承NSObject
类结构分析
在 oc 对象的本质与isa 中发现isa
是Class
类型的,Class
是objc_class*
,objc_class
是一个结构体,所有的Class底层实现都是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
//下面是一些方法省略
};
objc_class
继承objc_object
,objc_object
里面只有一个成员变量isa
,isa
具体是作用已经探究过。下面的三个成员变量具体的作用还未知,怎么去探究它呢?类的地址是知道的,那么就根据上面探究过的首地址+偏移值
来获取里面的成员变量的地址,然后获取值。但是偏移值需要知道当前变量之前的所有成员变量的大小
isa
结构体指针占8字节Class superclass
也是结构体指针占8字节cache_t cache
是结构体类型的大小,由结构体内成员变量决定, 16字节class_data_bits_t bits
知道前面三个成员变量大小,就可以得到bits的地址
cache_t
内存大小
typedef unsigned long uintptr_t;
#if __LP64__
typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits
#else
typedef uint16_t mask_t;
#endif
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
};
//下面是一些方法省略
};
cache_t
是结构体类型,有两个成员变量_bucketsAndMaybeMask
和一个联合体
_bucketsAndMaybeMask
是 uintptr_t无符长整型占8字节- 联合体里面有两个成员变量结构体和
_originalPreoptCache
,联合体的内存大小由成员变量中的最大变量类型决定 _originalPreoptCache
是结构体指针占8字节- 结构体中有
_maybeMask
,_flags
,_occupied
。_maybeMask
是uint32_t占 4字节,_flags
和_occupied
是uint16_t 各占2字节,结构体大小是8字节 cache_t
的内存大小是 8+8 或者是8+4+2+2都是16字节
小结:通过获取class_rw_t*
类型的data()
,将会拿到这个类的methods
、properties
、protocols
、deepCopy
、ro
等等信息
class_rw_t
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t witness;
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif
//省略了部分代码
explicit_atomic<uintptr_t> ro_or_rw_ext;
Class firstSubclass;
Class nextSiblingClass;
class_rw_ext_t *deepCopy(const class_ro_t *ro) {
return extAlloc(ro, true);
}
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
}
}
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
}
}
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
}
}
};
类的属性
成员变量获取流程:NSObject.class -> class_data_bits_t -> class_rw_t -> property_array_t -> property_list_t -> property_t
类的实例方法
实例方法获取流程:NSObject.class -> class_data_bits_t -> class_rw_t -> method_array_t -> method_list_t -> method_t -> big
成员变量
ivars
获取流程源码:NSObject.class -> class_data_bits_t -> class_rw_t -> class_ro_t -> ivar_list_t -> ivar_t
变量的底层实现是ivar_t
。存储在class_ro_t
中的变量列表里
系统会给属性自动生成一个带_
属性名变量,存储在class_ro_t
中的变量列表里
类方法
类方法获取流程:NSObject.class -> metaClass -> class_data_bits_t -> class_rw_t -> method_array_t -> method_list_t -> method_t -> big
结论:类方法存储在元类中
的方法列表里
源码
查看的源码是objc4-818.2.tar.gz