iOS开发底层之对象的本质-04
Posted iOS_developer_zhong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发底层之对象的本质-04相关的知识,希望对你有一定的参考价值。
对象的本质
把目标文件编译成C++文件。
比如: 把main.m文件编程成main.cpp文件,下面为终端命令
clang -rewrite-objc main.m -o main.cpp
提示:以下是本篇文章正文内容
一、对象的本质是什么?
对象的本质其实就是结构体,如何得出,请看下面的编译成C++后的源码。
1.初步了解对象的底层。
- 新建一个MyPerson对象,看看底层发生了什么?
// OC 源码
// 对象在底层的本质就是结构体
@interface MyPerson : NSObject
@property (nonatomic, strong) NSString *myName;
@end
//------------------------分割线--------------------------
// 编译成C++源码,部分展示
extern "C" unsigned long OBJC_IVAR_$_MyPerson$_myName;
struct MyPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_myName;
};
// 其实就是存放了一个isa
struct NSObject_IMPL {
Class isa;
};
// getter setter 方法
static NSString * _I_MyPerson_myName(MyPerson * self, SEL _cmd) {
return (*(NSString **)((char *)self + OBJC_IVAR_$_MyPerson$_myName));
}
static void _I_MyPerson_setMyName_(MyPerson * self, SEL _cmd, NSString *myName) {
(*(NSString **)((char *)self + OBJC_IVAR_$_MyPerson$_myName)) = myName;
}
// ivar 属性列表
static struct /*_ivar_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count;
struct _ivar_t ivar_list[1];
} _OBJC_$_INSTANCE_VARIABLES_MyPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_ivar_t),
1,
{{(unsigned long int *)&OBJC_IVAR_$_MyPerson$_myName, "_myName", "@\\"NSString\\"", 3, 8}}
};
// 方法列表
// @16@0:8 含义,后续会讲解
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[4];
} _OBJC_$_INSTANCE_METHODS_MyPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
4,
{{(struct objc_selector *)"myName", "@16@0:8", (void *)_I_MyPerson_myName},
{(struct objc_selector *)"setMyName:", "v24@0:8@16", (void *)_I_MyPerson_setMyName_},
{(struct objc_selector *)"myName", "@16@0:8", (void *)_I_MyPerson_myName},
{(struct objc_selector *)"setMyName:", "v24@0:8@16", (void *)_I_MyPerson_setMyName_}}
};
2. 联合体与位域
- 结构体与联合体的概念
结构体(struct)中所有变量是"共存"的, 优点是:所有的变量都会分配内存控件,也能给对应的变量赋值,缺点就是,分配内存空间是全部分配, 不管是否有使用。 全部分配。
联合体(union)是变量"互斥"的, 缺点就是新赋值的变量会覆盖上一个赋值的变量, 优点就是,使用更加精细灵活,节省内存空间。
- 结构体与联合体,实操源码
// 结构体 :共存
struct Teacher1 {
char *name;
int age;
double height ;
};
// 联合体 : 互斥
union Teacher2 {
char *name;
int age;
double height ;
};
//调用
int main(int argc, const char * argv[]) {
@autoreleasepool {
struct Teacher1 teacher1;
teacher1.name = "zgr";
teacher1.age = 18;
union Teacher2 teacher2;
teacher2.name = "zgr";
teacher2.age = 18;
NSLog(@"Hello, World!");
}
return 0;
}
2.1 通过lldb来打印给结构体与联合体的成员变量分别赋值后的结果。
运行结果反馈出了结构体的共存,联合体的互斥。
3.非常重要- isa 详解
- arm64-isa 位域赋值, objc源码中查询 注意看注释
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \\
uintptr_t nonpointer : 1; \\
uintptr_t has_assoc : 1; \\
uintptr_t has_cxx_dtor : 1; \\
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \\
uintptr_t magic : 6; \\
uintptr_t weakly_referenced : 1; \\
uintptr_t deallocating : 1; \\
uintptr_t has_sidetable_rc : 1; \\
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
// 解释
/*
nonpointer: 表示是否对isa指针开启指针优化。 0:纯isa指针, 1:不止是类的对象地址,isa还包含了类信息,对象的引用计数等。
has_assoc: 关联的对象标志位, 0没有,1存在
has_cxx_dtor: 表示是否有c++或者objc的析构器, 有,需要走析构逻辑,没有,可以更快的释放对象。
shiftcls: 存储类指针的值, 开启指针优化的情况下,在arm64架构中有33位用来存储类指针。 class信息就在这儿。
magic: 用于调试器判断当前对象是真的对象还是没有初始化控件。
weakly_referenced: 标志对象是否指向一个ARC的弱变量,没有弱引用的对象可以更快释放。
deallocating: 标志对象是否正在释放内存。
has_sidetable_rc: 当对象引用计数大于10,需要借用这个变量存储进位。
extra_rc: 引用计数值, 实际上是引用计数值减1. 比如:实际引用数是3, 此变量的值为2 。
*/
- isa的class的赋值反过程?
# define ISA_MASK 0x0000000ffffffff8ULL // 面具
// 操作
// 对象地址 & ISA_MASK ?
// 结果还是等于对象地址
- isa地址通过位移计算出对象内存地址
说明: 位移操作是确保读取的内存只剩下cls内存地址, 截图中是x86_64环境下的位移操作,arm64下则不同。
ios 是小端模式
所以内存地址的排列顺序从左往右为: 十七位+cls+三位
位移操作:(把右边的三位,与左边的十七位全部挤出去,只留下自己)
- 右移三位
- 左移二十位
- 右移十七位
- 得到的地址,就是cls地址
二. 命令记录
p/x 对象.class ( 打印类的地址,如 p/x myPerson.class )
以上是关于iOS开发底层之对象的本质-04的主要内容,如果未能解决你的问题,请参考以下文章