美文网首页
Runtime运行时一:类

Runtime运行时一:类

作者: Carson_Zhu | 来源:发表于2018-02-02 01:18 被阅读8次

    简介

    Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。

    这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc RuntimeObjc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

    objc_object

    objc_object是表示一个类的实例的结构体

    struct objc_object {
        Class isa  OBJC_ISA_AVAILABILITY;
    };
    
    • isa指针指向所属的类
      可以看到,这个结构体只有一个字体,即指向实例所属类的isa指针。当我们向一个Objective-C对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类。Runtime库会在类的方法列表及父类的方法列表中去寻找与消息对应的selector指向的方法。找到后即运行这个方法。
    Class

    Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针,也就意味着Class本身也是一个对象。它的定义如下:

    typedef struct objc_class *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;  // 类的版本信息,默认为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;
    
    • isa指针指向Meta Class(元类)
      既然类也是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针。那么这些就有一个问题了,这个isa指针指向什么呢?为了调用类方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就引出了Meta Class的概念
    Meta Class

    Meta Class是一个类对象的类,它存储着一个类的所有类方法。

    • isa指针指向基类Meta Class
      既然Meta Class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的Meta Classisa指向基类的Meta Class,以此作为它们的所属类。即任何NSObject继承体系下的Meta Class都使用NSObjectMeta Class作为自己的所属类,而基类的Meta Classisa指针是指向它自己。这样就形成了一个完美的闭环。

    动态生成

    既然Objective-C是一门动态语言,那么一切都可以在运行时动态创建。

    创建类

    参数一:父类
    参数二:名称
    参数三:开辟字节长度

    Class Student = objc_allocateClassPair([Person class], "Student", 0);
    
    创建成员变量

    参数一:类名
    参数二:名称
    参数三:开辟字节长度
    参数四:内存对齐方式
    参数五:参数类型 “@” 官方解释 An object (whether statically typed or typed id) (对象 静态类型或者id类型) 具体类型可参照官方文档

    class_addIvar(Student, "_studentID", sizeof(NSString *), log2(sizeof(NSString *)), "^NSString");
    class_addIvar(Student, "_classNumber", sizeof(NSInteger), log(sizeof(NSInteger)), "i");
    
    创建属性

    属性类别说明

    objc_property_attribute_t type = {"T", "@\"NSString\""}; // 类型
    objc_property_attribute_t iver = {"V", "_studentID"}; // 绑定的成员变量
    objc_property_attribute_t ownership = {"C", ""}; // 持有的参数
    objc_property_attribute_t nonatomic = {"N", ""};// 原子量
            
    objc_property_attribute_t attributes[] = {type, iver, ownership, nonatomic};
            
    // 给一个类添加一个属性,@1 类名, @2: 属性明, @3:属性的参数说明数组
    class_addProperty(Student, "sid", attributes, 4);
    
    创建方法

    参数一、类名
    参数二、SEL 添加的方法名字
    参数三、IMP指针 (IMP就是Implementation的缩写,它是指向一个方法实现的指针,每一个方法都有一个对应的IMP)
    参数四、其中types参数为"i@:@“,按顺序分别表示:具体类型可参照官方文档
    i 返回值类型int,若是v则表示void
    @ 参数id(self)
    : SEL(_cmd)
    @ id(str)
    V@:表示返回值是void 带有SEL参数 (An object (whether statically typed or typed id))

    class_addMethod(Student, @selector(test:), (IMP)test, "v@:^NSString");
    

    这里我们需要实现一个函数和一个方法

    void test(id self, SEL _cmd, NSString *str) {
        // 实现写在这里
    }
    
    - (void)test:(NSString *)str {
        NSLog(@"%@", str);
    }
    
    创建对象

    创建对象需要在系统注册

    objc_registerClassPair(Student);
    

    和创建成员变量方法一样,只是参数类型不一样

    BOOL isSuccess = class_addIvar(Student, "studentOne", sizeof(NSString *), 0, "@");
    
    成员变量赋值
    // 取到成员变量的结构体
    Ivar ivar = class_getInstanceVariable(Student, "_studentID");
    // 给成员变量赋值
    object_setIvar(studentOne, ivar, @"4321");
    // 从成员变量取到值
    id value = object_getIvar(studentOne, ivar);
    
    获取属性
    // 获取属性
    objc_property_t property = class_getProperty(Student, "sid");
    // 获取属性的名字
    const char *pName = property_getName(property);
    // 获取属性参数
    const char *pAtrributes = property_getAttributes(property);
    

    相关文章

      网友评论

          本文标题:Runtime运行时一:类

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