美文网首页
RunTime学习

RunTime学习

作者: Tony17 | 来源:发表于2020-02-28 08:39 被阅读0次

    前言

    Runtime 是OC作为动态语言的一大特性,在开发过程中围绕着这个特性我们可以做很多"黑魔法"般的事情,但是这是一个双刃剑,如果运用的好的话,确实会对程序有很大的帮助,但是如果滥用就会导致很多意想不到的情况。特别是在与三方库配合使用的时候,稍不留神就会引发灾难性的后果。今天来看下 Runtime 的实现逻辑。

    Runtime 简述

    在Runtime执行过程中,最重要的一个概念就是 isa。关于 isa 这个东西本篇不展开讲,简单理解为描述对象的指针就可以了。利用 Runtime 最大的作用就是在程序运行过程中动态替换对象的属性,方法等。知名的开源库 MJExtension就是是运用的Runtime的这些特性才得以实现的。

    如果要知道Runtime的实现原理,就需要先简单了解一下 OC 中 Class的结构

    Class 结构

    Class的大概结构图就如下图所示:

    runtime_class_struct.png

    其中methods中的原属都为method_t对象,method_t是对方法/函数的封装,结构如下:

    method_t.png

    参数解释:

    • IMP 代表函数的具体实现
      typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
    • SEL 代表方法/函数名,一般叫做选择器,底层结构和char *类似
      • 可以通过@selector()和sel_registerName()获得
      • 可以通过sel_getName()和NSStringFromSelector()转成字符串
      • 不同类中相同名字的方法所对应的方法选择器是相同的
        typedef struct objc_selector *SEL;
    • types 包含了函数的返回值,参数编码和字符串
    Code Meaning
    c A char
    i An int
    s A short
    l A long l is treated as a 32-bit quantity on 64-bit programs
    q A long long
    C An unsigned char
    I An unsigned int
    S An unsigned short
    L An unsigned long
    Q An unsigned long long
    f float
    d double
    B A C++ bool or a C99 _Boll
    v A void
    * A character string(char *)
    @ An object (whether statically typed or typed id)
    # A class object(Class)
    : A method selector(SEL)
    [array type] An array
    {name=type...} A structure
    (name=type...) A union
    bnum A bit field of num bits
    ^type A pointer to type
    ? An unknown type(among other things, this code is used for function pointers)

    方法缓存

    • 方法调用之后,如果没有缓存过,会缓存到缓存列表中去,父类的方法也会缓存到当前类的缓存列表中
    • 缓存列表容量不够的时候,会进行扩容,扩容方式为当前容量X2
    • 缓存列表扩容的时候,会清空当前已缓存的信息
    • 缓存列表结构为散列表

    实际运用

    • json-model 转换 (获取类的属性)
    • method-swizzle (class_addMethod,class_replaceMethod,method_exchangeImplementations 等方法)
    • 分类添加属性 (主要使用关联对象的方法)

    Runtime常用API

    • 动态创建一个类(参数:父类,类名,额外的内存空间)
      Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)

    • 注册一个类(要在类注册之前添加成员变量)
      void objc_registerClassPair(Class cls)

    • 销毁一个类
      void objc_disposeClassPair(Class cls)

    • 获取isa指向的Class
      Class object_getClass(id obj)

    • 设置isa指向的Class
      Class object_setClass(id obj, Class cls)

    • 判断一个OC对象是否为Class
      BOOL object_isClass(id obj)

    • 判断一个Class是否为元类
      BOOL class_isMetaClass(Class cls)

    • 获取父类
      Class class_getSuperclass(Class cls)

    • 获取一个实例变量信息
      Ivar class_getInstanceVariable(Class cls, const char *name)

    • 拷贝实例变量列表(最后需要调用free释放)
      Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

    • 设置和获取成员变量的值
      void object_setIvar(id obj, Ivar ivar, id value)
      id object_getIvar(id obj, Ivar ivar)

    • 动态添加成员变量(已经注册的类是不能动态添加成员变量的)
      BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)

    • 获取成员变量的相关信息
      const char *ivar_getName(Ivar v)
      const char *ivar_getTypeEncoding(Ivar v)

    • 获取一个属性
      objc_property_t class_getProperty(Class cls, const char *name)

    • 拷贝属性列表(最后需要调用free释放)
      objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

    • 动态添加属性
      BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
      unsigned int attributeCount)

    • 动态替换属性
      void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
      unsigned int attributeCount)

    • 获取属性的一些信息
      const char *property_getName(objc_property_t property)
      const char *property_getAttributes(objc_property_t property)

    • 获得一个实例方法、类方法
      Method class_getInstanceMethod(Class cls, SEL name)
      Method class_getClassMethod(Class cls, SEL name)

    • 方法实现相关操作
      IMP class_getMethodImplementation(Class cls, SEL name)
      IMP method_setImplementation(Method m, IMP imp)
      void method_exchangeImplementations(Method m1, Method m2)

    • 拷贝方法列表(最后需要调用free释放)
      Method *class_copyMethodList(Class cls, unsigned int *outCount)

    • 动态添加方法
      BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

    • 动态替换方法
      IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

    • 获取方法的相关信息(带有copy的需要调用free去释放)
      SEL method_getName(Method m)
      IMP method_getImplementation(Method m)
      const char *method_getTypeEncoding(Method m)
      unsigned int method_getNumberOfArguments(Method m)
      char *method_copyReturnType(Method m)
      char *method_copyArgumentType(Method m, unsigned int index)

    • 选择器相关
      const char *sel_getName(SEL sel)
      SEL sel_registerName(const char *str)

    • 用block作为方法实现
      IMP imp_implementationWithBlock(id block)
      id imp_getBlock(IMP anImp)
      BOOL imp_removeBlock(IMP anImp)

    最后

    以上就是本篇的内容,势必会有一些错误和遗漏,欢迎斧正~

    相关文章

      网友评论

          本文标题:RunTime学习

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