OC对象的本质

探寻OC对象的本质,我们平时编写的Objective-C代码,底层实现其实都是C\C++代码。

OC的对象结构都是通过基础C\C++的结构体实现的。 我们通过创建OC文件及对象,并将OC文件转化为C++文件来探寻OC对象的本质
OC如下代码:

#import <Foundation/Foundation.h>

int main(int argc, const char argv[]) {
@autoreleasepool {
NSObject
objc = [[NSObject alloc] init];
NSLog(@”Hello, World!”);
}
return 0;
}

我们通过命令行将OC的mian.m文件转化为c++文件。

clang -rewrite-objc main.m -o main.cpp // 这种方式没有指定架构例如arm64架构 其中cpp代表(c plus plus)
生成 main.cpp

我们可以指定架构模式的命令行,使用xcode工具 xcrun

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
生成 main-arm64.cpp

main-arm64.cpp 文件中搜索NSObjcet,可以找到NSObjcet_IMPL(IMPL代表 implementation 实现)

我们看一下NSObject_IMPL内部

struct NSObject_IMPL {
Class isa;
};
// 查看Class本质
typedef struct objc_class *Class;
我们发现Class其实就是一个指针,对象底层实现其实就是这个样子。

思考: 一个OC对象在内存中是如何布局的。 NSObjcet的底层实现,点击NSObjcet进入发现NSObject的内部实现

@interface NSObject {

#pragma clang diagnostic push

#pragma clang diagnostic ignored “-Wobjc-interface-ivars”
Class isa OBJC_ISA_AVAILABILITY;

#pragma clang diagnostic pop
}
@end

转化为c语言其实就是一个结构体

struct NSObject_IMPL {
Class isa;
};

那么这个结构体占多大的内存空间呢,我们发现这个结构体只有一个成员,isa指针,而指针在64位架构中占8个字节。也就是说一个NSObjec对象所占用的内存是8个字节。到这里我们已经可以基本解答第一个问题。但是我们发现NSObject对象中还有很多方法,那这些方法不占用内存空间吗?其实类的方法等也占用内存空间,但是这些方法所占用的存储空间并不在NSObject对象中。

为了探寻OC对象在内存中如何体现,我们来看下面一段代码

NSObject *objc = [[NSObject alloc] init];

上面一段代码在内存中如何体现的呢?上述一段代码中系统为NSObject对象分配8个字节的内存空间,用来存放一个成员isa指针。那么isa指针这个变量的地址就是结构体的地址,也就是NSObjcet对象的地址。
假设isa的地址为0x100400110,那么上述代码分配存储空间给NSObject对象,然后将存储空间的地址赋值给objc指针。objc存储的就是isa的地址。objc指向内存中NSObject对象地址,即指向内存中的结构体,也就是isa的位置。

@interface Student : NSObject{

@public
int _no;
int _age;

}
@end
@implementation Student

int main(int argc, const char * argv[]) {
@autoreleasepool {

    Student *stu = [[Student alloc] init];
    stu -> _no = 4;
    stu -> _age = 5;

    NSLog(@"%@",stu);
}
return 0;

}
@end

按照上述步骤同样生成c++文件。并查找Student,我们发现Student_IMPL

struct Student_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _no;
int _age;
};

发现第一个是 NSObject_IMPL的实现。而通过上面的实验我们知道NSObject_IMPL内部其实就是Class isa 那么我们假设 struct NSObject_IMPL NSObject_IVARS; 等价于 Class isa;

可以将上述代码转化为

struct Student_IMPL {
Class *isa;
int _no;
int _age;
};

##类

对象的类不仅描述了对象的数据:对象占用的内存大小,成员变量的类型和布局,也描述了对象的行为:对象能够响应的消息,实现的实力方法。实际上我们调用实例方法【receiver message】给对象发送一个消息的时候,这个对象能否响应这个消息就需要通过isa来这道它所属的类,才能知道

实例方法保存在类中,类方法保存在元类中的

元类也是对象 ,元类是根元类的实例对象。根元类isa是指向本身的

void prepare_load_methods(h+hi-