实例对象(id)
实例对象是我们对类对象alloc或者new操作时所创建的,在这个过程中会拷贝实例所属类的成员变量,但并不拷贝类定义的方法。
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
复制代码
objc_object这个结构体只有一个isa变量,指向实例对象所属的类。任何带有以指针开始并指向类结构的结构都可以被视作objc_object, 对象最重要的特点是可以给其发送消息。
类(Class)
typedef struct objc_class *Class;
复制代码
由此可见 ,Class是指向C的结构体objc_class的指针,我们再看一下objc_class的定义
元类(objc_class)
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
复制代码
- isa指针是和Class同类型的objc_class结构指针,类对象的指针指向其所属的类,即元类。元类中存储着类对象的类方法,当访问某个类的类方法时会通过该isa指针从元类中寻找方法对应的函数指针。
- super_class为该类所继承的父类对象,如果该类已经是最顶层的根类(如NSObject或NSProxy), 则 super_class为NULL。
- ivars是一个指向objc_ivar_list类型的指针,用来存储每一个实例变量的地址。
- info为运行期使用的一些位标识,比如:CLS_CLASS (0x1L)表示该类为普通类, CLS_META (0x2L)则表示该类为元类。
- methodLists用来存放方法列表,根据info中的标识信息,当该类为普通类时,存储的方法为实例方法;如果是元类则存储的类方法。
- cache用于缓存最近使用的方法。系统在调用方法时会先去cache中查找,在没有查找到时才会去methodLists中遍历获取需要的方法。
isa
是一个Class 类型的指针,每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)
实例、类、元类、isa 关系图:
由此可见,在给实例对象或类对象发送消息时,寻找方法列表的规则为:
- 当发送消息给实例对象时,消息是在寻找这个对象的类的方法列表(实例方法)
- 当发送消息给类对象时,消息是在寻找这个类的元类的方法列表(类方法)
所有元类都有一个根元类,比如所有NSObject的子类的元类都会以NSObject的元类作为他们的类。所有的元类使用根元类作为他们的类,根元类的元类则就是它自己,也就是说根元类的isa指针指向他自己。
总结:
object_getClass(实例对象) == [实例对象 class]
[类对象 class] == 类对象
object_getClass(类对象) == 类对象的isa == 元类
object_getClass(类对象) != [类对象 class]
复制代码