先从源码看下面是 id类的源码,#import<objc/objc.h>
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
下面是,NSObject.h
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
id是一种通用的对象类型,她可以用类存储属于任何类的对象,可以理解为万能指针,NSObject 和id都可以指向任何对象。
比如我们创建的一个对象或实例其实就是一个struct objc_object
结构体,而我们常用的id
也就是这个结构体的指针。
NSObject 和id都存在一个isa指针 Class isa OBJC_ISA_AVAILABILITY;
这个指针的定义如下:
class object(类对象)/metaclass(元类)
继续查看结构体objc_class
的定义
struct objc_class {
Class isa;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
}
struct objc_classs
结构体里存放的数据称为元数据(metadata)
,通过成员变量的名称我们可以猜测里面存放有指向父类的指针、类的名字、版本、实例大小、实例变量列表、方法列表、缓存、遵守的协议列表等,这些信息就足够创建一个实例了,该结构体的第一个成员变量也是isa
指针,这就说明了Class
本身其实也是一个对象,我们称之为类对象。
这个结构体第一个成员就是个isa指针,这个指针是指向哪里呢?
类对象
中的元数据
存储的都是如何创建一个实例的相关信息,那么类对象
和类方法
应该从哪里创建呢?就是从isa
指针指向的结构体创建,类对象
的isa
指针指向的我们称之为元类(metaclass)
,元类
中保存了创建类对象
以及类方法
所需的所有信息,因此整个结构应该如下图
通过上图我们可以清晰的看出来一个实例对象也就是struct objc_object
结构体它的isa
指针指向类对象
,类对象
的isa
指针指向了元类,super_class
指针指向了父类的类对象
,而元类
的super_class
指针指向了父类的元类
,那元类
的isa
指针又指向了什么?为了更清晰的表达直接使用一个大神画的图。
说起来就是subClass的isa 所有的元类对象(metaclass object)都指向 NSObject的元类对象,到头还是NSObject。一共三次:类对象->元类对象->NSObject元类对象。