美文网首页
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