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.初步了解对象的底层。

  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. 联合体与位域

  1. 结构体与联合体的概念
 结构体(struct)中所有变量是"共存"的, 优点是:所有的变量都会分配内存控件,也能给对应的变量赋值,缺点就是,分配内存空间是全部分配, 不管是否有使用。 全部分配。 
 联合体(union)是变量"互斥"的, 缺点就是新赋值的变量会覆盖上一个赋值的变量, 优点就是,使用更加精细灵活,节省内存空间。 
  1. 结构体与联合体,实操源码
// 结构体 :共存
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 详解

  1. 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 。 
*/
  1. isa的class的赋值反过程?
#   define ISA_MASK        0x0000000ffffffff8ULL  // 面具

// 操作 
// 对象地址 & ISA_MASK ?
// 结果还是等于对象地址
  1. isa地址通过位移计算出对象内存地址在这里插入图片描述
    在这里插入图片描述
说明: 位移操作是确保读取的内存只剩下cls内存地址, 截图中是x86_64环境下的位移操作,arm64下则不同。 
ios 是小端模式
所以内存地址的排列顺序从左往右为: 十七位+cls+三位

位移操作:(把右边的三位,与左边的十七位全部挤出去,只留下自己)

  1. 右移三位
  2. 左移二十位
  3. 右移十七位
  4. 得到的地址,就是cls地址

二. 命令记录

p/x 对象.class  ( 打印类的地址,如 p/x myPerson.class )

以上是关于iOS开发底层之对象的本质-04的主要内容,如果未能解决你的问题,请参考以下文章

iOS底层原理之alloc探究对象本质与神秘的isa

iOS底层探索之对象的本质和类的关联特性initIsa(下)

iOS底层原理 - Block本质探究

iOS开发系列-Block本质篇

iOS开发之结构体底层探索

iOS synchronized底层原理分析