本文的主要目的是分析 类 & 类的结构,整篇都是围绕一个类
展开的一些探索
1.类的分析之Class isa和Class superclass ---> isa走向和继承关系链
类的分析 主要是分析 isa
的走向 以及 类之间的继承
关系,注意对象之间
没有继承关系
哦
分析类之前提出几个问题
1.Class
到底是什么?Class
与类
之间的关系?
2.对象
的isa
和类
的isa
之间的区别?分别存储的是什么值?
3.对象方法
存储在类
中,那类方法
存储在哪里呢?如果一直有相应的类
来存储那么尽头在哪里呢?
4.isa
与supperClass
是什么关系? isa
到底有哪些作用?
5.类
在内存中到底存在几份
?
类的底层定义,runtime.h里早期类的定义,现在已经弃用
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; // isa
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE; // super_class 父类指针
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; //成员变量列表
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;//方法列表
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; //缓存
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;//协议列表
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
objc_object的部分代码
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA(bool authenticated = false);
// rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
Class rawISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
uintptr_t isaBits() const;
bool hasNonpointerIsa();
bool isTaggedPointer();
bool isTaggedPointerOrNil();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();
bool isClass();
// object may have associated objects?
bool hasAssociatedObjects();
void setHasAssociatedObjects();
// object may be weakly referenced?
bool isWeaklyReferenced();
void setWeaklyReferenced_nolock();
// object may have -.cxx_destruct implementation?
bool hasCxxDtor();
// Optimized calls to retain/release methods
id retain();
void release();
id autorelease();
// Implementations of retain/release methods
id rootRetain();
bool rootRelease();
id rootAutorelease();
bool rootTryRetain();
bool rootReleaseShouldDealloc();
uintptr_t rootRetainCount();
// Implementation of dealloc methods
bool rootIsDeallocating();
void clearDeallocating();
void rootDealloc();
};
类的新的定义,部分代码, objc-runtime-new.h文件里面
struct objc_class : objc_object {
// Class ISA; // isa 继承自objc_object
Class superclass; //父类指针
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();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
}
Class id宏定义
typedef struct objc_class *Class;
typedef struct objc_object *id;
总结:
1.Class
是objc_class
是类
,类
来自于底层objc_class
结构体
2.id
是objc_object
是对象
,即对象
来自于objc_object
结构体
3.objc_class : objc_object
,objc_class
继承自objc_object
结构体,objc_class
的isa
继承自objc_object
,所以,类
和对象都有Class isa
指针
4.类
有superclass
有继承关系,对象
没有superclass
没有继承关系
5.本篇博客研究类的 isa、superclass、bits
三个成员变量,很有规律性,各个源码版本略有差异
1.准备工作
main.m
里自定义类CJLPerson
,代码如下
// 协议 protocol
@protocol CJLPersonDelegate <NSObject>
//实例方法
- (void)sendDataToController:(NSMutableArray *)dataArray;
// 类方法
+ (void)sendString:(NSString *)string;
// 可选实例方法
@optional
- (void)showKeyboard;
// 可选类方法
@optional
+ (void)closeKeyboard;
@end
@interface CJLPerson : NSObject <CJLPersonDelegate> {
// 成员变量
NSString * hobby;
NSString * sex;
}
// 属性
@property (nonatomic, copy) NSString * cjl_name;
@property (nonatomic, copy) NSString * number;
// 实例方法
- (void)sayHello:(NSString *)hello;
- (void)sayWorld;
// 类方法
+ (void)sayBye;
+ (void)sayLove;
@end
@implementation CJLPerson
- (void)sayHello:(NSString *)hello {
}
- (void)sayWorld {
}
+ (void)sayBye {
}
+ (void)sayLove {
}
- (void)sendDataToController:(NSMutableArray *)dataArray {
}
- (void)showKeyboard {
}
+ (void)sendString:(NSString *)string {
}
调用方式
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
CJLPerson * person = [[CJLPerson alloc] init];
NSLog(@"person == %@", person);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
@end
2.元类
首先,我们先通过一个案例的lldb
调试先引入元类
,对象
的isa
指向类
,类
的isa
指向的就是元类
通过断点调试,lldb输出如下,相信说明见注释
我们由前面的内容知道对象的内存地址是第一个8字节是isa的值,其他后面的都是对应属性的值,假设都是NSString类型的属性,都是8字节,对象内存示意图如下
对象的内存地址和内存分布
{
0x0100000104c01418 :Class isa 值 第一个8字节
0x0100000104c01420 :name 值 第二个8字节
0x0100000104c01428:height 值 第三个8字节
0x0100000104c01430:weight 值 第四个8字节
0x0100000104c01438:XXX 值 依次类推
}
类的源码结构
struct objc_class : objc_object {
Class ISA; // Class 类型 8字节 继承自objc_object, 第一8字节是isa
Class superclass; // Class 类型 8字节, 第二8字节是superclass也就是父类
cache_t cache; // 16字节
class_data_bits_t bits; //
...
}
以上可知
1.对象
的第一个8
字节是isa
,
2.类
的第一个8
字节是isa
3.类
的第二个8
字节是supperclass
,也就是父类
4.对象
没有supperclass
,也就是说对象
没有继承关系
,只有类
有继承关系
(lldb) x/4gx person
0x600003705e40: 0x0100000104c014d9 0x0000000000000000 //0x0100000104c014d9 对象的isa
0x600003705e50: 0x0000000000000000 0x0000000000000000
(lldb) p/x 0x0100000104c014d9 & 0x0000000ffffffff8ULL // 对象的isa &上ISA_MASK
(unsigned long long) $1 = 0x0000000104c014d8 //类的16进制数值
(lldb) po 0x0000000104c014d8 //打印类的16进制数值为CJLPerson
CJLPerson
(lldb) p/x CJLPerson.class //p/x直接打印类的16进制数值,可以看到与上面的一致
(Class) $3 = 0x0000000104c014d8 CJLPerson
(lldb) x/4gx 0x0000000104c014d8 //打印类的4段内存
0x104c014d8: 0x0000000104c014b0 0x00000001c28fc628 //0x0000000104c014b0 类的isa
0x104c014e8: 0x0001600003705e60 0x0001802100000000
(lldb) p/x 0x0000000104c014b0 & 0x0000000ffffffff8ULL // 类的isa &上ISA_MASK
(unsigned long long) $4 = 0x0000000104c014b0// 类的isa &上ISA_MASK的值与没有&上ISA_MASK完全一致
// 说明类的isa 8字节64位中除了33位类信息之外其他全部为0
(lldb) po 0x0000000104c014b0 // 打印类的isa指向输出结果依然是CJLPerson
CJLPerson
//0x0000000104c014d8 CJLPerson,名字相同,16进制数值不同,很明显是两个类,对象isa指向的是类,CJLPerson类本身
//0x0000000104c014b0 CJLPerson,名字相同,16进制数值不同,很明显是两个类,类isa指向的是元类,
//CJLPerson的元类,只是名字相同而已,暂且标记为CJLPerson_Metal
// CJLPerson和CJLPerson的元类(CJLPerson_Metal)是两个不同的概念
(lldb) x/4gx 0x0000000104c014b0 //打印CJLPerson的元类的4段内存
0x104c014b0: 0x00000001c28fc600 0x00000001c28fc600
0x104c014c0: 0x0003600002258080 0x0002e03500000000
(lldb) po 0x00000001c28fc600 //输出CJLPerson_Metal的isa指向NSObject,此NSObject是NSObject的元类
NSObject // 即NSObject_Metal与NSObject是两个概念
(lldb) x/4gx 0x00000001c28fc600 // 继续输出NSObject_Metal的isa指向,依然指向自身
0x1c28fc600: 0x00000001c28fc600 0x00000001c28fc628
0x1c28fc610: 0x00036000022580c0 0x0003e03400000000
(lldb) x/4gx 0x00000001c28fc600 // 继续输出NSObject_Metal的isa指向,依然指向自身
0x1c28fc600: 0x00000001c28fc600 0x00000001c28fc628
0x1c28fc610: 0x00036000022580c0 0x0003e03400000000
(lldb) p/x NSObject.class //打印NSObject.class类本身
(Class) $7 = 0x00000001c28fc628 NSObject
(lldb)
//0x00000001c28fc628 NSObject
//0x00000001c28fc600 NSObject元类(NSObject_Metal)
// 这两个是不同的概念,不同的类
define ISA_MASK 0x0000000ffffffff8ULL
根据调试过程,我们产生了一个疑问:为什么图中的p/x 0x0100000104c014d9 & 0x0000000ffffffff8ULL
与 p/x 0x0000000104c014b0 & 0x0000000ffffffff8ULL
中的类信息打印出来的类名都是CJLPerson
,这两个CJLPerson
是什么关系呢?
0x0100000104c014d9
是person
对象的isa
指针地址,其&后得到的结果是 创建person
的类CJLPerson
0x0000000104c014b0
是CJLPerson
类的isa
的所存储的指针地址,即 CJLPerson
类的类的地址,在Apple中,我们简称CJLPerson类的类为元类
0x0100000104c014d9 & 0x0000000ffffffff8ULL
= 0x0000000104c014d8
(值
或者是首地址
不同) = CJLPerson
,类名相同
,这是CJLPerson类
0x0000000104c014b0 & 0x0000000ffffffff8ULL
= 0x0000000104c014b0
(值
或者是首地址
不同) = CJLPerson
,类名相同
,这是CJLPerson元类
,暂且标记为CJLPerson _metaClass
CJLPerson类
和CJLPerson _metaClass
是两个不同的类
,且每个
在内存中只有一份
,且内存地址
不同,
元类
和类
是两个不同的概念,只是体现出来的类名字
相同而已
所以,两个打印都是CJLPerson的根本原因就是因为元类导致的
3.元类的说明
下面来解释什么是元类,主要有以下几点说明:
我们都知道 对象
的isa
是指向类
,类
其实也是一个对象
,可以称为类对象
,其isa
指向苹果定义的元类
元类
是系统
给的,其定义
和创建
都是由编译器
完成,在这个过程中,类
的归属来自于元类
元类
是类对象 的类,每个类
都有一个独一无二的元类
用来存储 类方法
的相关信息。
元类
本身是没有名称
的,由于与类
相关联,所以使用了同类
名一样的名称
下面通过lldb命令来探索元类的走向,也就是isa的走位,如下图所示,可以得出一个关系链:
对象isa
---> 类isa
---> 元类isa
---> NSobject(根元类)
---> NSobject(根元类)
person
(对象) ---> CJLPerson
(类) ---> CJLPerson _metaClass
(CJLPerson元类) ---> NSobject_metaClass
(NSobject根元类)--->NSobject_metaClass
(根元类自身)
CJLPerson
不是CJLPerson_metaClass
(CJLPerson元类),内存地址
不同,但是每一个只有一份
NSobject
不是NSobject_metaClass
(根元类),内存地址
不同,但是每一个只有一份
4.isa走位图
5.LLDB调试 isa走位图
6.superclass指向
7.LLDB调试 superclass指向
8.苹果官方的isa走位以及继承关系图
9.LLDB调试 CJLTeacher ---> CJLPerson ---> NSObject 三级继承关系isa走位及superclass指向
新增类CJLTeacher
继承于CJLPerson
, CJLPerson
继承于NSObject
,调用如下
@interface CJLTeacher : CJLPerson
@end
@implementation CJLTeacher
@end
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
// ISA_MASK 0x0000000ffffffff8ULL
CJLTeacher * teacher = [[CJLTeacher alloc] init];
CJLPerson * person = [[CJLPerson alloc] init];
NSObject * obj = [[NSObject alloc] init];
NSLog(@"teacher == %@ person == %@ obj == %@", teacher, person, obj);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
LLDB调试,完美验证iOS系统的isa走位及继承关系图
10. clang 编译位cpp文件 查看isa 和 superclass指向
CJLTeacher
以及其元类isa
和superclass
指向
CJLPerson
以及其元类isa
和superclass
指向
NSObject根元类
被编译成OBJC_METACLASS_$_NSObject
CJLPerson元类
被编译成OBJC_METACLASS_$_CJLPerson
CJLTeacher元类
被编译成OBJC_METACLASS_$_CJLTeacher
NSObject
被编译成OBJC_CLASS_$_NSObject
CJLPerson
被编译成OBJC_CLASS_$_CJLPerson
static void OBJC_CLASS_SETUP_$_CJLTeacher(void ) {
OBJC_METACLASS_$_CJLTeacher.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_CJLTeacher.superclass = &OBJC_METACLASS_$_CJLPerson;
OBJC_METACLASS_$_CJLTeacher.cache = &_objc_empty_cache;
OBJC_CLASS_$_CJLTeacher.isa = &OBJC_METACLASS_$_CJLTeacher;
OBJC_CLASS_$_CJLTeacher.superclass = &OBJC_CLASS_$_CJLPerson;
OBJC_CLASS_$_CJLTeacher.cache = &_objc_empty_cache;
}
static void OBJC_CLASS_SETUP_$_CJLPerson(void ) {
OBJC_METACLASS_$_CJLPerson.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_CJLPerson.superclass = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_CJLPerson.cache = &_objc_empty_cache;
OBJC_CLASS_$_CJLPerson.isa = &OBJC_METACLASS_$_CJLPerson;
OBJC_CLASS_$_CJLPerson.superclass = &OBJC_CLASS_$_NSObject;
OBJC_CLASS_$_CJLPerson.cache = &_objc_empty_cache;
}
2.类的分析之类信息存储 ---> bits( class_data_bits_t 结构体类 )
以上研究了类的isa
走势图和superclass
继承关系图,那么类的其他信息比如方法、协议、属性、成员变量
存在什么地方呢?
cache_t cache
是方法缓存
很明显类的相关信息是存在class_data_bits_t bits
这个结构体成员变量里面的
下面探索 bits
里面怎么存储了方法、协议、属性、成员变量
等信息的,各个需要用到的结构体的部分代码如下,精简便于理解,不同版本略有差异,但是流程是一样的
1.objc_class
类结构体部分代码
struct objc_class : objc_object {
// Class ISA; // --> 继承自objc_object --> 8字节
Class superclass; // --> superclass 父类指针--> 8字节
cache_t cache; // 方法缓存 formerly cache pointer and vtable --> 16字节
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 class_data_bits_t {
// Values are the FAST_ flags above.
uintptr_t bits;
public:
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
};
-
class_rw_t
结构体部分代码
struct class_rw_t {
public:
const class_ro_t *ro() const { //ro() ---> 获取存储成员变量的相关结构体 ---> class_ro_t
auto v = get_ro_or_rwe(); // class_ro_t ---> 获取成员变量方法列表
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
const method_array_t methods() const { //methods()函数 ---> 获取方法列表
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 { //properties() ---> 获取属性列表
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};
}
}
};
-
method_t
结构体部分代码
struct method_t {
struct big { // method_t 内部又重新定义了一个 struct big 三个成员变量 SEL---types---IMP //同 method_t
SEL name;
const char *types;
MethodListIMP imp; // using MethodListIMP = IMP;
};
public:
big &big() const {
ASSERT(!isSmall());
return *(struct big *)this;
}
SEL name() const { // name() ---> 获取SEL
if (isSmall()) {
return (small().inSharedCache()
? (SEL)small().name.get()
: *(SEL *)small().name.get());
} else {
return big().name;
}
}
const char *types() const { // types() ---> 获取方法签名
return isSmall() ? small().types.get() : big().types;
}
IMP imp(bool needsLock) const { // imp(1) ---> 获取IMP
if (isSmall()) {
IMP imp = remappedImp(needsLock);
if (!imp)
imp = ptrauth_sign_unauthenticated(small().imp.get(),
ptrauth_key_function_pointer, 0);
return imp;
}
return big().imp;
}
};
-
property_t
结构体全部
struct property_t {
const char *name; // 名称
const char *attributes; // 特性
};
-
class_ro_t
结构体部分代码
struct class_ro_t {
const ivar_list_t * ivars; // 成员变量列表
}
-
ivar_t
结构体部分代码
struct ivar_t {
const char *name; //成员变量名称
const char *type; // 成员变量类型
};
8.protocol_t : objc_object
结构体部分代码,继承自objc_object
struct protocol_t : objc_object {
const char *mangledName; // 协议名称
struct protocol_list_t *protocols;
method_list_t *instanceMethods; // 实例方法列表
method_list_t *classMethods; // 类方法列表
method_list_t *optionalInstanceMethods;// 可选实例方法列表
method_list_t *optionalClassMethods;// 可选类方法列表
property_list_t *instanceProperties;
uint32_t size; // sizeof(protocol_t)
uint32_t flags;
};
核心思路 :
对应的结构体
---> 函数(解析内存结构)
---> 获取到其他结构体
---> 函数(解析内存结构)
---> 需要的结构体
---> 函数
10.实例方法method获取流程
结构体流程
objc_class(类)
---> class_data_bits_t
---> class_rw_t
--->method_t
函数流程
data()
---> methods()
---> name()
---> 获取SEL
data()
---> methods()
---> types()
---> 获取types 函数签名
data()
---> methods()
---> imp(1)
---> 获取IMP
整体流程
objc_class(类)
---> class_data_bits_t
---> data()
---> class_rw_t
---> methods()
---> method_t
method_t
---> name()
--->SEL
method_t
---> types()
---> 方法签名
method_t
--- >imp(1)
---> IMP
11.类方法method获取流程
结构体流程
objc_class(元类)
---> class_data_bits_t
---> class_rw_t
--->method_t
函数流程
data()
---> methods()
---> name()
---> 获取SEL
data()
---> methods()
---> types()
---> 获取types 函数签名
data()
---> methods()
---> imp(1)
---> 获取IMP
整体流程
objc_class(元类)
---> class_data_bits_t
---> data()
---> class_rw_t
---> methods()
---> method_t
method_t
---> name()
--->SEL
method_t
---> types()
---> 方法签名
method_t
--- >imp(1)
---> IMP
12.属性property获取流程
结构体流程
objc_class(类)
---> class_data_bits_t
---> class_rw_t
--->property_t
函数流程
data()
---> properties()
---> name
---> 获取属性名称
data()
---> properties()
---> attributes
---> 获取属性特性attributes
整体流程
objc_class(类)
---> class_data_bits_t
---> data()
---> class_rw_t
---> properties()
---> property_t
property_t
---> name
---> 获取属性名称
property_t
---> attributes
---> 获取属性特性attributes
13.成员变量ivar获取流程
结构体流程
objc_class(类)
---> class_data_bits_t
---> class_rw_t
--->class_ro_t
---> ivar_t
函数流程
data()
---> ro()
---> ivars
---> name
获取属性名称
data()
---> ro()
---> ivars
---> type
获取属性类型
整体流程
objc_class(类)
---> class_data_bits_t
---> data()
---> class_rw_t
--->ro()
---> class_ro_t
---> ivar_t
ivars
---> name
获取属性名称
ivar_t
---> type
---> 获取属性类型
14.协议protocol获取流程
结构体流程
objc_class(类)
---> class_data_bits_t
---> class_rw_t
--->protocol_t(对象)
---> method_t
函数流程
data()
---> protocols()
---> instanceMethods
---> 获取实例方法列表
instanceMethods
---> name()
--->SEL
instanceMethods
---> types()
--->方法签名
instanceMethods
---> imp(1)
--->IMP
同上
data()
---> protocols()
---> classMethods
---> 获取类方法列表
data()
---> protocols()
---> optionalInstanceMethods
---> 获取获取可选实例方法
data()
---> protocols()
---> optionalClassMethods
---> 获取获取可选类方法
整体流程
objc_class(类)
---> class_data_bits_t
---> data()
---> class_rw_t
---> protocols()
---> protocol_t(对象)
---> instanceMethods
instanceMethods
---> name()
--->SEL
instanceMethods
---> types()
--->方法签名
instanceMethods
---> imp(1)
--->IMP
15.LLDB调试实例方法method解析
16.LLDB调试类方法method解析
17.LLDB调试属性property解析
18.LLDB调试成员变量ivar解析
19.LLDB调试协议protocol解析
20.LLDB调试-实例方法instanceMethod调试过程
KCObjcBuild was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) p/x CJLPerson.class
(Class) $0 = 0x00000001000081c0 CJLPerson
(lldb) p (class_data_bits_t *) 0x00000001000081e0
(class_data_bits_t *) $1 = 0x00000001000081e0
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000101119d10
(lldb) p $2->methods()
(const method_array_t) $3 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100003ea0
}
arrayAndFlag = 4294983328
}
}
}
(lldb) p $3.list
(const method_list_t_authed_ptr<method_list_t>) $4 = {
ptr = 0x0000000100003ea0
}
(lldb) p $4.ptr
(method_list_t *const) $5 = 0x0000000100003ea0
(lldb) p *$5
(method_list_t) $6 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 2147483660, count = 5)
}
(lldb) p $6.get(0).name()
(SEL) $7 = "sayHello:"
(lldb) p $6.get(0).types()
(const char *) $8 = 0x0000000100003f7a "v24@0:8@16"
(lldb) p $6.get(0).imp(1)
(IMP) $9 = 0x0000000100003be0 (KCObjcBuild`-[CJLPerson sayHello:] at main.m:34)
(lldb) p $6.get(1).name()
(SEL) $10 = "sayWorld"
(lldb) p $6.get(1).types()
(const char *) $11 = 0x0000000100003f66 "v16@0:8"
(lldb) p $6.get(1).imp(1)
(IMP) $12 = 0x0000000100003c1c (KCObjcBuild`-[CJLPerson sayWorld] at main.m:38)
(lldb) p $6.get(2).name()
(SEL) $13 = "cjl_name"
(lldb) p $6.get(2).types()
(const char *) $14 = 0x0000000100003f85 "@16@0:8"
(lldb) p $6.get(2).imp(1)
(IMP) $15 = 0x0000000100003c30 (KCObjcBuild`-[CJLPerson cjl_name] at main.m:24)
(lldb) p $6.get(3).name()
(SEL) $16 = "setCjl_name:"
(lldb) p $6.get(3).types()
(const char *) $17 = 0x0000000100003f7a "v24@0:8@16"
(lldb) p $6.get(3).imp(1)
(IMP) $18 = 0x0000000100003c54 (KCObjcBuild`-[CJLPerson setCjl_name:] at main.m:24)
(lldb) p $6.get(4).name()
(SEL) $19 = ".cxx_destruct"
(lldb) p $6.get(5).name()
Assertion failed: (i < count), function get, file /Users/objc M1和因特尔芯片源码/objc源码/M1芯片mac/objc4-818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
LLDB调试-类方法classMethod调试过程
KCObjcBuild was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) p/x CJLPerson.class
(Class) $0 = 0x0000000100008200 CJLPerson
(lldb) x/2gx 0x0000000100008200
0x100008200: 0x00000001000081d8 0x0000000100379140
(lldb) po 0x00000001000081d8
CJLPerson
(lldb) p (class_data_bits_t *) 0x00000001000081f8
(class_data_bits_t *) $2 = 0x00000001000081f8
(lldb) p $2->data()
(class_rw_t *) $3 = 0x0000000101029b40
(lldb) p $3->methods()
(const method_array_t) $4 = {
list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
= {
list = {
ptr = 0x0000000100003e28
}
arrayAndFlag = 4294983208
}
}
}
(lldb) p $4.list
(const method_list_t_authed_ptr<method_list_t>) $5 = {
ptr = 0x0000000100003e28
}
(lldb) p $5.ptr
(method_list_t *const) $6 = 0x0000000100003e28
(lldb) p *$6
(method_list_t) $7 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 2147483660, count = 2)
}
(lldb) p $7.get(0).name()
(SEL) $8 = "sayBye"
(lldb) p $7.get(0).types()
(const char *) $9 = 0x0000000100003f5a "v16@0:8"
(lldb) p $7.get(0).imp(1)
(IMP) $10 = 0x0000000100003adc (KCObjcBuild`+[CJLPerson sayBye] at main.m:42)
(lldb) p $7.get(1).name()
(SEL) $11 = "sayLove"
(lldb) p $7.get(1).types()
(const char *) $12 = 0x0000000100003f5a "v16@0:8"
(lldb) p $7.get(1).imp(1)
(IMP) $13 = 0x0000000100003af0 (KCObjcBuild`+[CJLPerson sayLove] at main.m:46)
(lldb) p $7.get(2).name()
Assertion failed: (i < count), function get, file /Users/objc M1和因特尔芯片源码/objc源码/M1芯片mac/objc4-818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
LLDB调试-属性property调试过程
KCObjcBuild was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) p/x CJLPerson.class
(Class) $0 = 0x0000000100008208 CJLPerson
(lldb) p (class_data_bits_t *) 0x0000000100008228
(class_data_bits_t *) $1 = 0x0000000100008228
(lldb) p $1->data()
(class_rw_t *) $2 = 0x00000001008570f0
(lldb) p $2->properties()
(const property_array_t) $3 = {
list_array_tt<property_t, property_list_t, RawPtr> = {
= {
list = {
ptr = 0x0000000100008158
}
arrayAndFlag = 4295000408
}
}
}
(lldb) p $3.list
(const RawPtr<property_list_t>) $4 = {
ptr = 0x0000000100008158
}
(lldb) p $4.ptr
(property_list_t *const) $5 = 0x0000000100008158
(lldb) p *$5
(property_list_t) $6 = {
entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $6.get(0).name
(const char *) $7 = 0x0000000100003f1c "cjl_name"
(lldb) p $6.get(0).attributes
(const char *) $8 = 0x0000000100003eb7 "T@\"NSString\",C,N,V_cjl_name"
(lldb) p $6.get(1).name
(const char *) $9 = 0x0000000100003f32 "number"
(lldb) p $6.get(1).attributes
(const char *) $10 = 0x0000000100003ed3 "T@\"NSString\",C,N,V_number"
(lldb) p $6.get(2).name
Assertion failed: (i < count), function get, file /Users/objc M1和因特尔芯片源码/objc源码/M1芯片mac/objc4-818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
LLDB调试-成员变量ivar调试过程
KCObjcBuild was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) p/x CJLPerson.class
(Class) $0 = 0x0000000100008200 CJLPerson
(lldb) p (class_data_bits_t *) 0x0000000100008220
(class_data_bits_t *) $1 = 0x0000000100008220
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000105137810
(lldb) p $2->ro()
(const class_ro_t *) $3 = 0x0000000100008080
(lldb) p $3->ivars
(const ivar_list_t *const) $4 = 0x00000001000080c8
(lldb) p *$4
(const ivar_list_t) $5 = {
entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 4)
}
(lldb) p $5.get(0).name
(const char *) $6 = 0x0000000100003ef5 "hobby"
(lldb) p $5.get(0).type
(const char *) $7 = 0x0000000100003f62 "@\"NSString\""
(lldb) p $5.get(1).name
(const char *) $8 = 0x0000000100003efb "sex"
(lldb) p $5.get(1).type
(const char *) $9 = 0x0000000100003f62 "@\"NSString\""
(lldb) p $5.get(2).name
(const char *) $10 = 0x0000000100003eff "_cjl_name"
(lldb) p $5.get(2).type
(const char *) $11 = 0x0000000100003f62 "@\"NSString\""
(lldb) p $5.get(3).name
(const char *) $12 = 0x0000000100003f09 "_number"
(lldb) p $5.get(3).type
(const char *) $13 = 0x0000000100003f62 "@\"NSString\""
(lldb) p $5.get(4).name
Assertion failed: (i < count), function get, file /Users/objc M1和因特尔芯片源码/objc源码/M1芯片mac/objc4-818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb)
LLDB调试-协议protocol调试过程
KCObjcBuild was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) p/x CJLPerson.class
(Class) $0 = 0x0000000100008600 CJLPerson
(lldb) p (class_data_bits_t *) 0x0000000100008620
(class_data_bits_t *) $1 = 0x0000000100008620
(lldb) p $1->data()
(class_rw_t *) $2 = 0x0000000100957f50
(lldb) p $2->protocols()
(const protocol_array_t) $3 = {
list_array_tt<unsigned long, protocol_list_t, RawPtr> = {
= {
list = {
ptr = 0x0000000100008410
}
arrayAndFlag = 4295001104
}
}
}
(lldb) p $3.list
(const RawPtr<protocol_list_t>) $4 = {
ptr = 0x0000000100008410
}
(lldb) p $4.ptr
(protocol_list_t *const) $5 = 0x0000000100008410
(lldb) p *$5
(protocol_list_t) $6 = (count = 1, list = protocol_ref_t [] @ 0x000000012921a7c8)
(lldb) p $6.list[0]
(protocol_ref_t) $7 = 4295001744
(lldb) p (protocol_t *)$7
(protocol_t *) $8 = 0x0000000100008690
(lldb) p *$8
(protocol_t) $9 = {
objc_object = {
isa = {
bits = 4298608840
cls = Protocol
= {
nonpointer = 0
has_assoc = 0
has_cxx_dtor = 0
shiftcls = 537326105
magic = 0
weakly_referenced = 0
unused = 0
has_sidetable_rc = 0
extra_rc = 0
}
}
}
mangledName = 0x0000000100003c4d "CJLPersonDelegate"
protocols = 0x0000000100008310
instanceMethods = 0x0000000100008328
classMethods = 0x0000000100008348
optionalInstanceMethods = 0x0000000100008368
optionalClassMethods = 0x0000000100008388
instanceProperties = nil
size = 96
flags = 0
_extendedMethodTypes = 0x00000001000083a8
_demangledName = 0x0000000000000000
_classProperties = nil
}
(lldb) p/x 4298608840
(long) $10 = 0x00000001003790c8
(lldb) p/x 0x00000001003790c8 & 0x0000000ffffffff8ULL
(unsigned long long) $11 = 0x00000001003790c8
(lldb) po 0x00000001003790c8
Protocol
(lldb) p $9.instanceMethods
(method_list_t *) $13 = 0x0000000100008328
(lldb) p *$13
(method_list_t) $14 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 24, count = 1)
}
(lldb) p $14.get(0).name()
(SEL) $15 = "sendDataToController:"
(lldb) p $14.get(0).types()
(const char *) $16 = 0x0000000100003d50 "v24@0:8@16"
(lldb) p $14.get(0).imp(1)
(IMP) $17 = 0x0000000000000000
(lldb) p $9.classMethods
(method_list_t *) $18 = 0x0000000100008348
(lldb) p *$18
(method_list_t) $19 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 24, count = 1)
}
(lldb) p $19.get(0).name()
(SEL) $20 = "sendString:"
(lldb) p $19.get(0).types()
(const char *) $21 = 0x0000000100003d50 "v24@0:8@16"
(lldb) p $19.get(0).imp(1)
(IMP) $22 = 0x0000000000000000
(lldb) p $9.optionalInstanceMethods
(method_list_t *) $23 = 0x0000000100008368
(lldb) p *$23
(method_list_t) $24 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 24, count = 1)
}
(lldb) p $24.get(0).name()
(SEL) $25 = "showKeyboard"
(lldb) p $24.get(0).types()
(const char *) $26 = 0x0000000100003d48 "v16@0:8"
(lldb) p $24.get(0).imp(1)
(IMP) $27 = 0x0000000000000000
(lldb) p $9.optionalClassMethods
(method_list_t *) $28 = 0x0000000100008388
(lldb) p *$28
(method_list_t) $29 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 24, count = 1)
}
(lldb) p $29.get(0).name()
(SEL) $30 = "closeKeyboard"
(lldb) p $29.get(0).types()
(const char *) $31 = 0x0000000100003d48 "v16@0:8"
(lldb) p $29.get(0).imp(1)
(IMP) $32 = 0x0000000000000000
(lldb)
bits存储类信息的共同点
无论方法、属性、协议、成员变量
都放在了对应结构体的数组里,method_list_t
、property_list_t
、ivar_list_t
、protocol_list_t
,说明这些是有序
而且是值为真
LLDB
调试获取xxxx_list_t
里面的元素方式是p $5.get(0)
p $5.get(1)
...
p $5.get(N)
,get(index)
下标取法(圆括号+下标
)
那么接下来objc_class
里面非常重要的cache
是不是也是这样的存储方式呢?
(method_list_t) $6 = {
entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 2147483660, count = 5)
}
(property_list_t) $6 = {
entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(const ivar_list_t) $5 = {
entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 4)
}
(protocol_list_t) $6 = (count = 1, list = protocol_ref_t [] @ 0x000000012921a7c8)
3.isa、superclass、bits总结
** objc_class、objc_objcet、Class**
1.Class
是objc_class
是类
,类
来自于底层objc_class
结构体
2.id
是objc_object
是对象
,即对象
来自于objc_object
结构体
3.objc_class : objc_object
,objc_class
继承自objc_object
结构体,objc_class
的isa
继承自objc_object
,所以,类
和对象都有Class isa
指针
4.类
有superclass
有继承关系,对象
没有superclass
没有继承关系
元类
1.我们都知道 对象
的isa
是指向类
,类
其实也是一个对象
,可以称为类对象
,其isa
指向苹果定义的元类
2.元类
是系统
给的,其定义
和创建
都是由编译器
完成,在这个过程中,类
的归属来自于元类
3.元类
是类对象 的类,每个类
都有一个独一无二的元类
用来存储 类方法
的相关信息。
元类
本身是没有名称
的,由于与类
相关联,所以使用了同类
名一样的名称,但是本质和底层编译的名称是不一样的
4.CJLPerson
不是CJLPerson_metaClass
(CJLPerson元类),内存地址
不同,但是每一个只有一份
5.NSobject
不是NSobject_metaClass
(根元类),内存地址
不同,但是每一个只有一份
** isa**
对象
---> 类
---> 元类
---> NSobject(根元类)
---> NSobject(根元类)
superclass
1.只有类有继承关系,对象没有继承关系
子类
---> 父类
---> ...
---> NSObject
---> nil
子元类
--->父元类
---> ...
---> NSObject(根元类)
---> NSObject
---> nil
bits
1.实例方法
在类
里面,类方法
在元类
里面,类方法
相当于元类
的实例方法
,由于只有实例方法
和类方法
,所以,根元类
里面是没有方法列表
的
2.成员变量
列表里面有属性
,属性
列表里面没有成员变量
3.实例方法列表
包含属性
的setter
和getter
方法
4.实例对象
来自于objc_object
结构体
5.实例方法
、类方法
、协议
、属性
、成员变量
都存在对应类
或者元类
的objc_class
--->class_data_bits_t bits
成员变量里面
6.协议
是一个对象
继承自objc_object
结构体,协议
里面通过各种方法列表
存储协议方法
问题
1.Class
到底是什么?Class
与类
之间的关系?
Class
就是类
,也是类的首地址-指针
,存储内容是类名
,类似于数组名和数组首地址
2.对象
的isa
和类
的isa
之间的区别?分别存储的是什么值?
类的isa
64位
中只在对应的33位
存储类的首地址
,对象的isa 64位
中除了类信息还有其他信息,nonpointer = 0
的话,对象isa
只存储类信息,但是多数对象是nonpointer = 1的
3.对象方法
存储在类
中,那类方法
存储在哪里呢?如果一直有相应的类
来存储那么尽头在哪里呢?
对象方法
存储在类
中,类方法
存储在元类
中,由于只有类方法
和类方法
,所以,根元类里面是没有方法列表的
4.isa
与superclass
是什么关系? isa
到底有哪些作用?
isa
与superclass
都是Class
类型的64位
指针,都是存储类的指针
,没有直接的关系,isa
偏向于数据的操作逻辑属于谁,即方法
存储在哪里,找到后去操作数据,superclass
偏向于父类
在哪里,即更高级的操作逻辑属于谁,superclass
是帮助isa
在不同层级的父类中查找操作逻辑
5.类
在内存中到底存在几份
?
类
在内存中只有一份,类
和元类
虽然看着名字一样,但是本质是两个独立的类,内存空间
、底层编译
都是不同的