runtime - iOS类对象、实例对象、元类对象

理解类与对象的本质对于掌握一门语言是至关重要的,本文将从结构类型的角度探讨OC的类对象、实例对象、元类对象(Meta Class)。

我们先看一张图:


iOS类、实例、元类关系图.jpg
  • 每个 Class 都有一个 isa 指针指向一个唯一的 Meta Class
  • 每一个 Meta Class 的 isa 指针都指向最上层的 Meta Class,即 NSObject 的 MetaClass,而最上层的 MetaClass 的 isa 指针又指向自己

1.类对象

类对象是由程序员定义并在运行时由编译器创建的,它没有自己的实例变量,这里需要注意的是类的成员变量和实例方法列表是属于实例对象的,但其存储于类对象当中的。我们在objc.h下看看Class的定义:

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

可见,Class是指向C的结构体objc_class的指针,我们再看一下objc_class的定义(runtime.h):

struct objc_class {
    Class _Nonnull isa;                                     // 指向所属类的指针(_Nonnull)
    Class _Nullable super_class;                      // 父类  
    const char * _Nonnull name;                      // 类名(_Nonnull)
    long version;                                              // 类的版本信息(默认为0)   
    long info;                                                   // 类信息(供运行期使用的一些位标识)   
    long instance_size;                                    // 该类的实例变量大小
    struct objc_ivar_list * _Nullable ivars;        // 该类的成员变量链表
    struct objc_method_list * _Nullable * _Nullable methodLists;  // 方法定义的链表                  
    struct objc_cache * _Nonnull cache;                        // 方法缓存
    struct objc_protocol_list * _Nullable protocols;        // 协议链表
} ;
  • 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中遍历获取需要的方法。

2.实例对象

实例对象是我们对类对象alloc或者new操作时所创建的,在这个过程中会拷贝实例所属类的成员变量,但并不拷贝类定义的方法。调用实例方法时,系统会根据实例的isa指针去类的方法列表及父类的方法列表中寻找与消息对应的selector指向的方法。同样的,我们也来看下其定义(objc.h):

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

objc_object这个结构体只有一个isa变量,指向实例对象所属的类。任何带有以指针开始并指向类结构的结构都可以被视作objc_object, 对象最重要的特点是可以给其发送消息. NSObject类的alloc和allocWithZone:方法使用函数class_createInstance来创建objc_object数据结构。

/// A pointer to an instance of a class.
typedef struct objc_object *id;

id是一个objc_object结构类型的指针。该类型的对象可以转换为任何一种对象,类似于C语言中void *指针类型的作用(objc.h)。

3.元类对象(MetaClass)

顾名思义,元类对象即是描述类对象的类,每个类都有自己的元类,也就是结构体objc_class中isa指向的类。Objective-C的类方法是使用元类的根本原因,因为其中存储着对应的类对象调用的方法即类方法。


类存储示意图.jpg

由此可见,在给实例对象或类对象发送消息时,寻找方法列表的规则为:

*当发送消息给实例对象时,消息是在寻找这个对象的类的方法列表(实例方法)

*当发送消息给类对象时,消息是在寻找这个类的元类的方法列表(类方法)

所有元类都有一个根元类,比如所有NSObject的子类的元类都会以NSObject的元类作为他们的类。所有的元类使用根元类作为他们的类,根元类的元类则就是它自己,也就是说根元类的isa指针指向他自己。

这里我们可以进一步研究一下官方技术文档runtime.h:

OBJC_EXPORT Class _Nullable
object_getClass(id _Nullable obj) 
    OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);

这里object_getClass与NSObect.h中的类方法 +(Class)class;和实例方法+ (Class)class;有什么不同呢?请看源码:

Class object_getClass(id obj) {
    return _object_getClass(obj);
}

static inline Class _object_getClass(id obj) {

    #if SUPPORT_TAGGED_POINTERS

    if (OBJ_IS_TAGGED_PTR(obj)){
        uint8_t slotNumber = ((uint8_t)(uint64_t) obj) & 0x0F;
        Class isa = _objc_tagged_isa_table[slotNumber];
        return isa;
    }

    #endif

        if (obj) return obj->isa;   
        else return Nil;

}

_object_getClass函数就是返回对象的isa指针,也就是返回该对象所指向的所属类。

+ (Class)class {
    return self; // 返回自身指针
}

- (Class)class {
    return object_getClass(self); // 调用'object_getClass'返回isa指针
}

总结一下实例对象,类对象以及元类对象之间的isa指向和继承关系的规则为:
规则一: 实例对象的isa指向该类,类的isa指向元类(metaClass)
规则二: 类的superClass指向其父类,如果该类为根类则值为nil
规则三: 元类的isa指向根元类,如果该元类是根元类则指向自身
规则四: 元类的superClass指向父元类,若根元类则指向该根类

参考文章

  1. [格物致知iOS类与对象] https://mp.weixin.qq.com/s/iBELEyUfnShnLhS5xJh4mQ

2.[清晰理解Objective-C元类]http://blog.csdn.net/beclosedtomyheart/article/details/50164353

3.[Objective-C Runtime 运行时之一:类与对象]http://southpeak.github.io/2014/10/25/objective-c-runtime-1/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容