美文网首页
iOS OC源码剖析对象本质

iOS OC源码剖析对象本质

作者: 一眼万年的星空 | 来源:发表于2021-09-25 18:13 被阅读0次

类的底层实现

先写一个 Person 类:

@interface Person : NSObject
@property (nonatomic, copy) NSString *p_name;
@property (nonatomic, assign) int p_age;

- (void)p_instanceMethod1;
@end

@implementation Person
- (void)p_instanceMethod1{
    NSLog(@"%s",__func__);
}
@end

使用 clang 编译器, clang -rewrite-objc Person.m -o Person.cpp 将 Person.m 编译成 Person.cpp 文件,部分代码如下:

/// 1: Person 类型的底层结构
struct NSObject_IMPL {
  Class isa;
};

struct Person_IMPL {
  struct NSObject_IMPL NSObject_IVARS;
  int _p_age;
  NSString * _Nonnull _p_name;
};

/// 2: p_name 属性的底层结构
// get
static NSString * _Nonnull _I_Person_p_name(Person * self, SEL _cmd) { return (*(NSString * _Nonnull *)((char *)self + OBJC_IVAR_$_Person$_p_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
// set
static void _I_Person_setP_name_(Person * self, SEL _cmd, NSString * _Nonnull p_name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _p_name), (id)p_name, 0, 1); }

/// 3: p_age 类型的底层结构 
// get
static int _I_Person_p_age(Person * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_Person$_p_age)); }
// set
static void _I_Person_setP_age_(Person * self, SEL _cmd, int p_age) { (*(int *)((char *)self + OBJC_IVAR_$_Person$_p_age)) = p_age; }

/// 4: p_instanceMethod1 方法的底层结构
static void _I_Person_p_instanceMethod1(Person * self, SEL _cmd) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_86_0y_j3bzj65z6vw6hy1chw_4m0000gp_T_Person_f010c0_mi_0,__func__);
}

● NSObject 类被编译成了 NSObject_IMPL 的结构体。
● Person 类被编译成了 Person_IMPL 的结构体。
● Person 类的内部还增加了一个 NSObject_IMPL 的结构体
○ 我们知道 Person 继承于 NSObject, 所以它的底层实现中是第一个成员是父类的结构体,就是底层继承的实现方式。用这样的方式拥有父类所有的成员变量。
○ NSObject_IMPL 是 NSObject 类的编译后的结构体,它的内部只有一个 Class 类型的 isa 成员变量。我们知道 isa 是 isa_t 类型的,那为什么在这里定义成 Class 类型呢?这是为了更加直观的提现出它代表的是类的信息,所以在获取isa 的方法中,将它强制转换成了Class 类型, 代码如下:

inline Class objc_object::ISA() {

    ...
    
    return (Class)(isa.bits & ISA_MASK)
}
  • 总结:
  • 类的底层实现是结构体。
  • 继承是通过把父类的结构体声明为本类结构体的第一个成员变量实现的。

isa_t 的类型

联合体: 所有成员可以是不同的类型,但是公用一块内存区域,设置了一个成员变量就会覆盖另一个成员变量的数据。优点是节省空间。

union isa_t { //联合体
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    //提供了cls 和 bits ,两者是互斥关系
    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

isa 指针占用8字节,64位。64位中不同的位代表不同的含义:

isa 指针占用8字节

对象与类的 isa 的指向关系

对象与类的 isa 的指向关系

青山不改,绿水长流,后会有期,感谢每一位佳人的支持!

相关文章

网友评论

      本文标题:iOS OC源码剖析对象本质

      本文链接:https://www.haomeiwen.com/subject/hcixnltx.html