美文网首页iOS面试专题
iOS知识加固(一)-Runtime篇

iOS知识加固(一)-Runtime篇

作者: 与安君 | 来源:发表于2020-03-30 22:09 被阅读0次

    我只是知识的搬运工,为了应对面试和巩固知识体系,简化和整理了有关runtime的知识点,以求能快速理解和记忆。

    (一)Runtime概念

    1. Runtime是用C、C++、汇编写的一套框架
    2. Objective-C语言是以Runtime为核心对C的扩展
    3. Runtime使得Objective-C拥有面向对象和动态的特性
    4. Runtime的核心就是消息机制(Messaging)

    Runtime形成的动态特性:

    1. 数据类型推迟到运行时确定
    2. 方法推迟到运行时进行选择和变更

    以我个人的理解,程序是到运行时将我们所写的OC语言转换成C语言,进而转换成计算机识别的汇编语言,而由OCC转换时,Runtime库根据我们的代码联系上下文形成明确的指令。

    消息机制秉承万物皆对象的思想,将类、实例对象、方法等当做一个消息指令:哪个对象,执行了哪个方法,附带了哪些参数,主谓宾集齐便凑成一句完整的话传递给计算机。

    1.1 消息传递

    OC中类、对象以及方法本质都是结构体,这个结构体就是一个信息集合的单位,OC底层实现中涉及以下几个概念:

    • 类对象(objc_class)
    • 实例(objc_object)
    • 元类(Meta Class)
    • Method(objc_method)
    • SEL(objc_selector)
    • IMP
    • 类缓存(objc_cache)
    • Category(objc_category)

    1.1.1 isa指针

    所有的实例对象其实都是同样的结构体(objc_object),id也是这个结构体类型,故能指向所有对象,而这个objc_object结构体内只有一个指针isa,指向这个对象的类对象(objc_class),类对象的结构体里包含属性列表(ivars)、方法列表(methodLists)等,类对象的isa指针指向类对象的类,称之为元类(metaclass),另外类对象在编译期间产生了实例对象,是单例,所以isa表达了类和实例的逻辑关系(参见下图,详细底层代码请阅读结尾博文)

    • 对象(instance)的isa指向类(class object)
    • 类(class object)的isa指向元类(metaclass)
    • 元类(metaclass)的isa指向根元类(root metaclass)
    isa指针指向

    1.1.2 method

    Method是方法的结构体,其中包含SELIMP和方法类型属性,个人理解SEL是方法索引,IMP是方法的具体实现。

    1.1.3 类缓存(objc_cache)和Category(objc_category)

    一个class 往往只有 20% 的函数会被经常调用,可能占总调用次数的 80% 。每个消息都需要遍历一次objc_method_list 并不合理。如果把经常被调用的函数缓存下来,那可以大大提高函数查询的效率。这也就是objc_class 中另一个重要成员objc_cache做的事情。
    Category是表示一个指向分类的结构体的指针,其结构体内包含实例方法集合(instanceMethods)、类方法集合(classMethods)、协议集合(protocols)、属性集合(instanceProperties)、要拓展的类(cls)和类名称。

    1.2 消息转发

    消息传递过程中如果没有找到方法,系统给出挽回的三次机会。

    1.2.1 动态方法解析

    首先,Objective-C运行时会调用+(BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:(SEL)sel,让你有机会提供一个函数实现。如果你添加了函数并返回YES, 那运行时系统就会重新启动一次消息发送的过程。询问是否有动态添加方法来进行处理。

    1.2.2 备用接收者

    如果目标对象实现了-(id)forwardingTargetForSelector:(SEL)aSelector,Runtime 这时就会调用这个方法,给你把这个消息转发给其他对象的机会。

    1.2.3 完整消息转发(消息重定向)

    如果在上一步还不能处理未知消息,则唯一能做的就是启用完整的消息转发机制了。
    首先它会发送-methodSignatureForSelector:消息获得函数的参数和返回值类型。如果-methodSignatureForSelector:返回nilRuntime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送-forwardInvocation:消息给目标对象。

    (二)API

    • objc_msgSend(对象, @selector(方法),参数)
    • objc_getClass("类名", sel):返回当前类,当你找的类不存在,返回nil;
    • objc_lookUpClass("类名", sel):返回当前类,当你找的类不存在,返回nil;
    • objc_getRequiredClass("类名", sel):返回当前类,当你要找的类不存在的话会闪退,慎用。
    • object_getClass("类名", sel):通过对象返回当前类
    • class_addMethod([Person class], sel, (IMP)eat, "v@:@"):1.类类型;2.方法编号;3.方法实现,函数指针;4.返回值类型(c语言字符串),看文档
    • Ivar *ivars = class_copyIvarList([Person class], &count)
    • const char *name = ivar_getName(ivar)
    • free(ivars)
    • method_exchangeImplementations(Method, Method)

    (三)应用

    • 关联对象(Objective-C Associated Objects)给分类增加属性(objc_setAssociatedObject)
    • 方法魔法(Method Swizzling)方法添加和替换和KVO实现
    • 消息转发(热更新)解决Bug(JSPatch)
    • 实现NSCoding的自动归档和自动解档
    • 实现字典和模型的自动转换(MJExtension)

    练习

    1. isa指针指向问题
        BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
        BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
        BOOL res3 = [(id)[Person class] isKindOfClass:[NSObject class]];
        BOOL res4 = [(id)[Person class] isMemberOfClass:[NSObject class]];
        BOOL res5 = [(id)[Person class] isKindOfClass:[Person class]];
        BOOL res6 = [(id)[Person class] isMemberOfClass:[Person class]];
        NSLog(@"\n%d\n%d\n%d\n%d\n%d\n%d",res1,res2,res3,res4,res5,res6);
    
    1. 利用Runtime,在程序运行的过程中,动态创建一个类;
    2. 利用Runtime,在程序运行的过程中,动态创建一个类的属性/方法;
    3. 遍历一个类的所有成员变量;

    声明:参考以下博文,经过自己修改加工,为记录学习使用
    iOS Runtime详解
    iOS Runtime《一》 类Class 相关
    你真的明白isKindOfClass 和 isMemberOfClass 的区别么?
    深入理解iOS开发中的isa指针
    iOS消息机制相关
    iOS Runtime《一》 类Class 相关
    解读objc_msgSend

    相关文章

      网友评论

        本文标题:iOS知识加固(一)-Runtime篇

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