浅析IOS中isa指针的作用

在objective-c语言中,isa指针看名称指的是“是一个”的意思。isa指针是一个指针,具体到代码中,如果是对象,对象中的isa指针是指向的它的类对象。

/// 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;

如图中所示,任意对象类型都是struct objc_object  *指针的别名。通过观察该结构体变量,发现该结构体中只有一个Class类型的变量,它就是OC对象最基本的一个属性了。那么这个isa指针是用来做什么的呢?通过以上代码,可以发现对象的isa指针类型又是另外一个结构体指针类型struct objc_class *。接下来继续看这个结构体有什么内容:

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

从这个结构体中我们可以看出,这个结构体中同样有isa指针,这个指针类型就是这个结构体本身。那么可以大致了解到OC类对象是通过递归的方式来找到它的根类对象的。除了这个isa指针以外,还有其他的一些属性:指向父类对象的指针,名字、版本、描述信息、实例占用内存大小、实例变量列表、方法列表、缓存、遵守的协议列表等。通过这些属性,就可以得到这个类所有的相关信息了。因此,对象的isa指针指向的可以称之为类对象,程序运行时它就指向描述了这个对象所属的具体类型,而不是id这种动态类型。这样对象就可以知道刚才结构体中的所有成员信息了。例如父类是哪个,实例变量有哪些,实例方法有哪些,遵守的协议等。但是这还不够,因为对象还有类方法,类变量可以使用,所以类对象也有个isa指针,它指向的就是它的元类。元类中就包含了类对象创建所需要的所有信息。并且这些信息与对象创建不同的是在编译期就已经确定了。也就是说类对象在程序编译时就确定了。类对象和元类也有相同点,比如他们都有父类指针super_class,元类的父类指针指向的是元类的父亲元类,层层递进,直到指向NSObject这个OC的Root Class(meta)。然后这个根元类的isa指针指向的是它本身,不知道是啥意思。然后用个图来表示就是(自己懒得画了,图是转载来的):

举个例子理解该图:(->表示继承关系)

假设 有继承关系:A->B->C->NSObject,有句代码:

A *a = [A new];
B *b = [B new];
C *c = [C new];
NSObject *root = [NSObject new];

那么a这个实例变量就相当于上图中的Instance of Subclass,b和c就相当于上图中的Instance of Superclass,root就是Instance of Rootclass。它们的super_class指针就是指向的对应的父类对象。

Class aClass = [a class];
Class bClass = [b class];
Class cClass = [c class];
Class rootClass = [root class];

通过实例变量的class方法就可以得到它们的类对象。也就是它们isa指针指向的内容。根据图中继承关系可以表示为:

aClass -> bClass -> cClass -> rootClass

这也就是类对象的super_class指向的内容。

然后要想获得元类就不是通过类对象调用class方法得到了,因为类对象调用class方法得到的是它本身。应该调用的是下面这个方法:

Class aMetaClass = object_getClass(aClass);
Class bMetaClass = object_getClass(bClass);
Class cMetaClass = object_getClass(cClass);
Class rootMetaClass = object_getClass(rootClass);

通过以上这个方法,就可以获取该类对象所对应的元类。前文说到类对象记录了类对象的所有信息,最常用的就是类方法。这个元类就是类对象isa指针指向的内容了。元类之间也有

aMetaClass->bMetaClas->cMetaClass->rootMetaClass这种继承关系存在。

而且,元类isa指针指向的内容就都是相同的了,全都是指向的rootMetaClass。连rootMetaClass它自身isa指针指向的也是它自己。rootMetaClass中定义的就是NSObject类的类方法了,以及NSObject类的内部信息(例如实例方法列表,实例变量列表)。

而NSObject元类就是通过继承NSObject拿到的NSObject的对象信息的。因此,才会有NSObject元类继承自NSObject类这么一条。也说明了在OC中所有的类的根类都是NSObject类。至于NSObject类的父类,那就不存在了。所以是指向的nil。还有NSObject元类的isa指针指向自身,这个可以理解为就是一种面向对象概念——万物皆对象,最终形成一个闭环。

写在最后

通过以上分析,可以了解到isa指针的作用就是描述oc对象的所有信息的。通过这些充足的信息,可以创建出一个结构完整的对象。

 

参考链接:https://www.jianshu.com/p/9e975a1cab93

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章