01-OC对象的底层实现之alloc、init、new源码解读

简介: 01-OC对象的底层实现之alloc、init、new源码解读

1. OC对象的底层实现?

Objective-C的面向对象都是基于C/C++的数据结构实现的,接下来我们来探究一下OC对象的底层实现;

1.1 NSObject的底层实现

首先在main函数里面定义一个obj对象:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        NSObject *obj = [[NSObject alloc] init];
    }
    return 0;
}

将main.m转换为c++代码,通过如下命令:


xcrun -sdk iphoneos clang -arch arm64 -F Foundation.framework -rewrite-objc main.m -o main.cpp

查看main.cpp文件,会发现这样一个结构体:

struct NSObject_IMPL {
  Class isa;
};

我们查看NSObject对象的声明:

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}

通过对比我们会发现一个NSObject对象实际上就是一个结构体,通过objc的源码看到Class的定义如下,实际上它就是一个指向结构体的指针,故isa是一个指针类型;


typedef struct objc_class *Class;

1.2 自定义对象的底层实现

我们定义一个对象

@interface Person : NSObject {
    @public
    int age;
    int height;
}
@end
@implementation Person
@end

通过1.1中的命令,再来看一下它的底层实现:

struct Person_IMPL {
  struct NSObject_IMPL NSObject_IVARS;
  int age;
  int height;
};

而NSObject_IMPL的实现如下:

struct NSObject_IMPL {
  Class isa;
};

则Person的最终实现可以理解为:

struct Person_IMPL {
  Class isa;
  int age;
  int height;
};

使用如下代码验证一下p所指向的对象就是Person_IMPL这个结构体,从打印结果可以看出确实如此

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [[Person alloc] init];
        p->age = 4;
        p->height = 10;
        struct Person_IMPL *p_imp = (__bridge struct Person_IMPL *)(p);
        NSLog(@"%d", p_imp->age);//打印结果:4
    }
    return 0;
}

1.3 自定义对象的嵌套底层实现


@interface Person : NSObject {
    @public
    int age;
}
@end
@implementation Person
@end
@interface Student : Person {
    @public
    int height;
}
@end
@implementation Student
@end

通过1.1中的命令,再来看一下它的底层实现:

struct NSObject_IMPL {
    Class isa;
};
struct Person_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    int age;
};
struct Student_IMPL {
    struct Person_IMPL Person_IVARS;
    int height;
};

而Student最终可以理解为

struct Student_IMPL {
    Class isa;
    int age;
    int height;
};

2.  alloc源码解读

2.1 创建一个Person对象,其中Person类中无任何成员变量

2.2 进入到alloc方法的源码实现中

2.3 跳转到_objc_rootAlloc函数中

2.4 callAlloc实现


hasCustomAWZ为是否实现了allocWithZone方法

// class or superclass has default alloc/allocWithZone: implementation
// Note this is is stored in the metaclass.
#define FAST_CACHE_HAS_DEFAULT_AWZ    (1<<14)
bool hasCustomAWZ() const {
    return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}

2.5 执行_objc_rootAllocWithZone方法

2.6 执行_class_createInstanceFromZone方法

先看size = cls->instanceSize(extraBytes),其中extraBytes为0,这里执行到了cache.fastInstanceSize(extraBytes),如果走到了下面会看到如果分配的size小于16的话,size会强制设置为16


接着看fastInstanceSize之后会执行到align16函数,16字节对齐算法,会发现size就是为16;

实际上类所分配的实际内存最低都为16的倍数,这一点是从操作系统的层面去考虑的,为了加快cpu的读写速度,另一方面,也为了避免数据错乱,如果感兴趣的可以下载libmalloc源码自行查看;

接下来会调用calloc以及isa的处理等,这里不再深入分析,至此整个alloc流程结束;

3. init源码解读

调用init方法(实例方法的init)接着会来到下方,然后整个流程结束

我们会发现整个流程什么都没做,苹果这样设计的目的是什么呢?实际上这是苹果的一种设计模式就是为了将来我们在使用的时候,可以在重写init的内部做一些自定义的操作;

- (instancetype)init {
    if (self = [super init]) {
        //...
    }
    return self;
}

4. new源码解读

调用new的时候,会发现内部调用了callAlloc又调用了init函数,会发现又来到了callAlloc函数,接下来的整个过程和alloc过程一致,实际上调用new就相当于调用了alloc - init函数;

线


相关文章
|
2月前
|
Swift
Swift 中 struct(结构体)和 class(类)的区别
【10月更文挑战第10天】理解 struct 和 class 的区别对于正确使用 Swift 语言进行编程非常重要。在实际开发中,需要根据具体的需求和场景来选择合适的数据类型,以充分发挥它们的优势,提高代码的质量和效率。
|
2月前
|
Java
Optional源码分析(涉及Objects源码和Stream源码)
本文分析了Java中Optional类的源码,包括其内部的Objects.requireNonNull方法、EMPTY定义、构造方法、ofNullable方法、isEmpty方法以及如何与Stream类交互,展示了Optional类如何避免空指针异常并提供流式操作。
41 0
Optional源码分析(涉及Objects源码和Stream源码)
|
7月前
|
编译器 C++
OC如何实现函数参数对象的地址传
OC如何实现函数参数对象的地址传
47 0
|
Swift
OC 和 swift 创建单例方法
OC 和 swift 创建单例方法
331 0
JavaSE面试题——类初始化 & 实例初始化
JavaSE面试题——类初始化 & 实例初始化
JavaSE面试题——类初始化 & 实例初始化
|
Swift
Swift实用小册08:Class类的Struct结构体的使用
Swift实用小册08:Class类的Struct结构体的使用
276 0
Swift实用小册08:Class类的Struct结构体的使用
|
存储 算法 安全
iOS-底层原理 02:alloc & init & new 源码分析
iOS-底层原理 02:alloc & init & new 源码分析
144 0
iOS-底层原理 02:alloc & init & new 源码分析
|
存储 缓存 iOS开发
iOS底层原理:OC对象底层探索之alloc初探(二)
简介: iOS开发的小伙伴们对 [XXX alloc] init] 都不陌生,可以说 alloc 和 init 贯穿我们整个的开发过程中。那么在OC对象的底层,到底做了哪些操作呢?今天我们就来探索一下 alloc 底层的工作流程。
iOS底层原理:OC对象底层探索之alloc初探(二)
|
iOS开发
iOS底层原理:OC对象底层探索之alloc初探(一)
iOS开发的小伙伴们对 [XXX alloc] init] 都不陌生,可以说 alloc 和 init 贯穿我们整个的开发过程中。那么在OC对象的底层,到底做了哪些操作呢?今天我们就来探索一下 alloc 底层的工作流程。
iOS底层原理:OC对象底层探索之alloc初探(一)
|
Java 编译器 程序员
从JVM 源码看init和clinit到底什么区别
从JVM 源码看init和clinit到底什么区别
157 0
从JVM 源码看init和clinit到底什么区别