类与对象

2017-06-12  本文已影响0人  cmhfx1

目前iOS中,objc_class与objc_object使用的是后两个定义。

struct objc_class : objc_object {

    // Class ISA;

    Class superclass;

    cache_t cache;             // formerly cache pointer and vtable

    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

}

struct objc_object {

    private:

    isa_t isa;

}

这些结构体代表了类和对象在runtime中的数据结构

typedef struct objc_class *Class;

typedef struct objc_object *id;

使用重定义,Class 指向objc_class结构体的指针,id  指向objc_object结构体的指针

id obj;

Class cls;

定义的均是的指针变量

struct objc_class : objc_object,这说明每一个类实际上也是一个对象,有一个is a的指针

每一个对象都有一个is a的指针,通过该指针,我们能找到对象所属类。每一个类也有一个is a的指针,也是一个对象,那么,它也必须是另一个类的实例,这个类就是元类。元类也是一个对象,那么元类的is a指针又指向了哪里?

为了设计上的完整,所有的元类的is a指针都会指向一个根元类,根元类本身的is a指针指向自己,这样就形成了一个闭环。图片参考 iOS开发进阶 p217

通过上图,我们可以得出以下结论

1 类的类是元类

2 类的根类是NSObjet,NSObject的父类是nil

3 元类同样存在继承关系,元类的父类等价于父类的元类(类方法查找过程中的必须)

4 元类的根类是NSObjet的元类,NSObjet的元类isa指向自身。

5 NSObjet的元类的父类是NSObjet

每个类的类对象和元类对象 都仅有一个

消息发送机制,是对对象发送消息。也就是方法

@interface NSObject {

    Class isa  OBJC_ISA_AVAILABILITY;

}

由于继承关系,每个类都会有一个is a指针。

Person *ps = [Person new];

之前我的理解是创建一个结构体的指针(Class cls,Class经过重定义,创建出的变量,是指向objc_class的指针)。后来,又想到了C++中类和结构体的区别,然后整个人就懵逼了。

这里,是一个疑问,OC中的类本质是不是一个结构体。这里,一些解释是类比着结构体,比如我们每创建一个类实例,就像定义了一个对应结构的结构体变量,可能会有些不当,但有助于理解。在Runtime之外,还是说类和对象比较合适点。

类中定义了实例方法,元类中定义了类方法。

实例方法的调用规则是,根据is a指针找到类,如果该类没有定义一个方法的实现,则根据继承关系,向它的父类继续查找,

类方法的调用原则,当一个类方法被调用时,根据is a指针找到元类,元类首先会查找自身有没有该类方法的实现,如果没有,则元类会向它的父类查找该方法,这样可以一直找到继承链的头。

所以,为了保证父类的类方法在子类中被调用,所有子类的元类都会继承父类的元类,换而言之,类对象和元类对象有着同样的继承关系。

虽然有些东西被废弃了,但是原理是相通的,我们仍能从中获得一些有价值的信息。

struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存

例如,方法缓存。这里先说下相通的原理,后面会详细说道,优化后的缓存

cache 为方法调用的性能进行优化。通俗地讲,每当实例对象接收到一个消息时,它不会直接在isa指向的类的方法列表中遍历查找能够响应消息的方法,因为这样效率太低了,而是优先在Cache中查找。Runtime 系统会把被调用的方法存到Cache中(理论上讲一个方法如果被调用,那么它有可能今后还会被调用)如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率

上一篇下一篇

猜你喜欢

热点阅读