iOS底层探究-06:isa与类关联的原理

2020-11-05  本文已影响0人  对你的微笑纯属礼貌_e31

先来了解一个编译器:clang

对象的本质是什么

@interface LCPerson : NSObject
@property (nonatomic, copy) NSString *name;
@end

@implementation LCPerson
@end
//1、将 main.m 编译成 main.cpp
clang -rewrite-objc main.m -o main.cpp

//2、将 ViewController.m 编译成  ViewController.cpp
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot / /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.7.sdk ViewController.m

//以下两种方式是通过指定架构模式的命令行,使用xcode工具 xcrun
//3、模拟器文件编译
- xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp 

//4、真机文件编译
- xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main- arm64.cpp 
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m
#ifndef _REWRITER_typedef_LCPerson
#define _REWRITER_typedef_LCPerson
typedef struct objc_object LCPerson;
typedef struct {} _objc_exc_LCPerson;
#endif

extern "C" unsigned long OBJC_IVAR_$_LCPerson$_name;

// 定义的类在底层编译成了结构体
struct LCPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_name;
};

// @property (nonatomic, copy) NSString *name;
/* @end */


// @implementation LCPerson

// name的get方法
static NSString * _I_LCPerson_name(LCPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LCPerson$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
// name的set方法
static void _I_LCPerson_setName_(LCPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LCPerson, _name), (id)name, 0, 1); }
// @end
结论:OC对象的本质 其实就是 结构体

objc_setProperty 源码探索

除了LCPerson的底层定义,我们发现还有属性 name对应的setget 方法,如下图所示,其中set方法的实现依赖于runtime中的objc_setProperty

通过对objc_setProperty的底层源码探索,有以下几点说明:

下图是上层、隔离层、底层之间的关系

cls 与 类 的关联原理

在此之前,先了解什么是联合体,为什么isa的类型isa_t是使用联合体定义

联合体(union)

构造数据类型的方式有以下两种:

结构体

结构体是指把不同的数据组合成一个整体,其变量是共存的,变量不管是否使用,都会分配内存。

联合体

联合体也是由不同的数据类型组成,但其变量互斥的,所有的成员共占一段内存。而且共用体采用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会将原来成员的值覆盖掉

优点:所有成员共用一段内存,使内存的使用更为精细灵活,同时也节省内存空间

缺点:包容性弱

两者的区别

isa的类型 isa_t

以下是isa指针的类型isa_t的定义,从定义中可以看出是通过联合体(union)定义的。

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

isa_t类型使用联合体的原因也是基于内存优化的考虑,这里的内存优化是指在isa指针中通过char + 位域(即二进制中每一位均可表示不同的信息)的原理实现。通常来说,isa指针占用的内存大小是8字节,即64位,已经足够存储很多的信息了,这样可以极大的节省内存,以提高性能

isa_t的定义中可以看出:

针对两种不同平台,其isa的存储情况如图所示

上一篇下一篇

猜你喜欢

热点阅读