结构模型

作者: natewang | 来源:发表于2020-02-16 21:09 被阅读0次

    结构模型

    1. 介绍下runtime的内存模型(isa、对象、类、metaclass、结构体的存储信息等)
    Class:
    typedef struct objc_class *Class;
    
    struct objc_class {
    
    Class isa;  //指向meta_class
    
    Class super_class;     //指向父类
    
    const char* name;
    
    long version;
    
    long info;
    
    long instance_size;
    
    struct objc_ivar_list *ivars; //类的成员变量,使用数组存储,使用中基本不变化(只有动态生成的类才能添加成员变量Ivar),存取效率高。
    
    struct objc_method_list **methodLists;  //类的成员方法,使用链表存储。使用中可能会增加方法,使用链表存储。
    
    struct objc_cache *cache;   //类的方法缓存。
    
    struct objc_protocol_list *protocols;  //类遵守的协议。   
    
    };
    
    对象
    struct objc_object {
    
    Class isa; //指向对象所属的类。
    
    };
    
    
    1. 为什么要设计metaclass
      元类保存了类方法的列表
    1. class_copyIvarList & class_copyPropertyList区别
      class_copyPropertyList返回的仅仅是对象类的属性(@property申明的属性),而class_copyIvarList返回类的所有属性和变量(包括在@interface大括号中声明的变量)

    2. class_rw_t 和 class_ro_t 的区别
      ObjC 类中的属性、方法还有遵循的协议等信息都保存在 class_rw_t 中:其中还有一个指向常量的指针 ro,其中存储了当前类在编译期就已经确定的属性、方法以及遵循的协议。

    3. category如何被加载的,两个category的load方法的加载顺序,两个
      category的同名方法的加载顺序

    struct objc_class {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__
        Class super_class                       OBJC2_UNAVAILABLE;  // 父类
            const char *name                        OBJC2_UNAVAILABLE;  // 类名
            long version                                OBJC2_UNAVAILABLE;  // 类的版本信息,默认0
            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;
    
    struct category_t {
        const char *name;
        classref_t cls;
        struct method_list_t *instanceMethods;    //存储实例方法
        struct method_list_t *classMethods;        //存储类方法
        struct protocol_list_t *protocols;            //协议
        struct property_list_t *instanceProperties;//属性
        // Fields below this point are not always present on disk.
        struct property_list_t *_classProperties;
    
        method_list_t *methodsForMeta(bool isMeta) {
            if (isMeta) return classMethods;
            else return instanceMethods;
        }
    
        property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
    };
    
    

    分类的实现原理是将category中的方法,属性,协议数据放在category_t结构体中,然后将结构体内的方法列表拷贝到类对象的方法列表中。

    category的+load执行顺序是根据编译顺序决定的

    1. category & extension区别,能给NSObject添加Extension吗,结果如何
      Category的小括号中有名字,而Extension没有;
      Category只能扩充方法,不能扩充成员变量和属性;
      如果Category声明了声明了一个属性,那么Category只会生成这个属性的set,get方法的声明,也就不是会实现.
    1. 消息转发机制,消息转发机制和其他语言的消息机制优劣对比
      1.category
      2.运行时
      3.消息机制
      4.可以和C,C++,swift混和编程
      1.不支持命名空间
      2.不支持运算符重载
      3.不支持多重继承
      4.使用动态运行时类型,所有的方法都是函数点用,很多编译时的优化方法都用不到,如内联函数

    2. 在方法调用的时候,方法查询-> 动态解析-> 消息转发 之前做了什么
      1、正常判空处理
      2、TAGGED_POINTERS判断(后面文章再一起探究)
      3、通过isa指针拿到他的class(class中存储它的方法以及方法缓存)
      4、CacheLookup 查看方法缓存

    3. IMP、SEL、Method的区别和使用场景
      SEL
      SEL方法选择器,表示一个selector的指针
      无论什么类里,只要方法名相同,SEL就相同。项目里的所有SEL都保存在一个NSSet集合里(NSSet集合里的元素不能重复),所以查找对应方法,只要找到对应的SEL就可以了。
      SEL实际是根据方法名hash化了的字符串
      IMP
      定义:函数指针,指向方法实现的首地址。
      Method
      Method定义如下:它主要是用语描述类里面的方法

    typedef struct objc_method *Method;
    objc_method结构体定义如下
    
    struct objc_method {
        SEL method_name                              OBJC2_UNAVAILABLE;//方法名
        char *method_types                           OBJC2_UNAVAILABLE;//参数返回值字符串描述
        IMP method_imp                               OBJC2_UNAVAILABLE;//方法的实现
    }    
    从上述代码可以看出,Method是一个结构体,包含了SEL和IMP成员变量。
    实际上,相当于在SEL和IMP之间做了一个映射,有了Method,SEL就可以找到对应的IMP,从而调用方法。
    
    1. load、initialize方法的区别什么?在继承关系中他们有什么区别
      load和initialize会被自动调用,不能手动调用它们。
      子类实现了load和initialize的话,会隐式调用父类的load和initialize方法
      load和initialize方法内部使用了锁,因此它们是线程安全的。
      2.2 不同点
      子类中没有实现load方法的话,不会调用父类的load方法;而子类如果没有实现initialize方法的话,也会自动调用父类的initialize方法。
      load方法是在类被装在进来的时候就会调用,initialize在第一次给某个类发送消息时调用(比如实例化一个对象),并且只会调用一次,是懒加载模式,如果这个类一直没有使用,就不回调用到initialize方法。
      load
      父类先于子类调用
      类先于分类调用
      initialize 只会在对应类的方法第一次被调用时,如果一个子类没有实现 +initialize 方法,那么父类的实现是会被执行多次的,如果一个类的分类实现了 +initialize 方法,那么就会对这个类中的实现造成覆盖。

    相关文章

      网友评论

        本文标题:结构模型

        本文链接:https://www.haomeiwen.com/subject/hammfhtx.html