Objective-C 对象的本质是什么

作为一个iOS开发,接触最多的可能就是Objective-C语言了,众所周知Objective-C是一种面向对象的语言,苹果用C/C++为其封装了成员变量、方法的存储和方法调用逻辑,但是具体的实现并没有暴露给我们。

分析之前,需要先新建个Command Line Tool工程,然后再main文件中写入以下代码:

@interface Ghost : NSObject
{
    int age;
}
@end

@implementation Ghost
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Ghost *ghost = [[Ghost alloc] init];
    }
    return 0;
}

然后需要把它转成C/C++代码,打开终端,进入main文件所在的目录,执行以下命令

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

这个命令的意思是,把main.m文件中的代码,转换成iOS平台对应的C++代码。接下来打开main_arm64.cpp文件,搜索类名 Ghost,会找到Ghost_IMPL的结构体如下

typedef struct objc_object Ghost;
struct Ghost_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
        int age;
};

从这里不难发现Objective-C对象的本质就是objc_object类型的结构体。结构体里面有一个NSObject_IMPL类型的结构体和一个int类型名字为age的变量,这个NSObject_IMPL又是什么呢?可以在main_arm64.cpp文件里面搜索NSObject_IMPL,会发现一个结构体如下

typedef struct objc_object NSObject;
struct NSObject_IMPL {
	Class isa;
};

不难猜出,这个应该是NSobject类的底层实现,通过Xcode进入NSObject的头文件,会发现类的实现是这样的

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

上下对比下,可以证明猜测是正确的。并且可以看到NSObject对象里面只有一个 Class 类型的isa指针。

这个Class类型又是什么呢,可以通过Xcode进入objc.h找到如下代码

typedef struct objc_class *Class;

struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

typedef struct objc_object *id;

这里能看到Class是struct objc_class类型的指针,同时可以看到id是struct objc_object类型的指针。

那么struct objc_class内部又是什么样子的结构呢,Xcode并不能跳到定义的地方,这时候就需要查看苹果开源的代码了。

从这里下载最新源码,版本号最大的就是苹果开源的最新的代码。下载完成后解压,我下载的(objc4-818.2),用Xcode打开工程。这时候搜索struct objc_class,发现有两个文件定义了这个结构体(objc-runtime-new.h和objc-runtime-old.h),忽略old直接看new,可以找到如下定义(line 1688)

struct objc_class : objc_object {
    //省略...
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;   
    //省略...
}

可以看到objc_class是继承于objc_object的结构体,然后再搜索下struct objc_object,会在objc-private.h找到如下定义

struct objc_object {
private:
    isa_t isa;
//省略 ...
}

发现isa指针并不是Class类型的了,那是因为苹果在64位系统,为了让指针存储更多的数据,isa指针优化成union isa_t的类型,找到isa_t的定义

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

private:
    Class cls;
    void setClass(Class cls, objc_object *obj);
    Class getClass(bool authenticated);
    Class getDecodedClass(bool authenticated);
};

进入getClass方法里面,会发现 clsbits &= ISA_MASK,可以得知现在指向Class的指针需要再按位与ISA_MASK后才可以得到。

综上,Objective-C 中

1、实例对象是objc_object类型的结构体,里面包含isa指针和成员变量。

2、类对象是objc_class类型的结构体,因为继承于objc_object类型,所以同样包含isa指针,还有superclass指针等类的一些信息。

3、元类也是Class类型,同样也是objc_class类型的结构体。