美文网首页
iOS Runtime!!!

iOS Runtime!!!

作者: 大宝的爱情 | 来源:发表于2021-03-10 19:30 被阅读0次

    一,什么是Runtime?

    runtime就是运行时,OC是运行时语言,指不是编译的时候决定调用谁,而是运行到那的时候才决定

    二,Runtime消息传递

    一个对象的方法 [obj test],编译器转成消息发送objc_msgSend(obj, test)

    Runtime时执行的流程是这样的:

    ①.首先,通过obj的isa指针找到它的class;
    ②.在class的method list找test;
    ③.如果class中没到test,继续往它的superclass中找 ;
    ④.一旦找到test这个函数,就去执行它的实现IMP

    解释:根据isa找到本类,在本类列表里找,没有就在父类中找,一旦找到,就去执行它的实现IMP(期间有个缓存过程,下次也会先从缓存中找,没有再去缓存,使得找到更加迅速),找不到就进入消息转发相关流程(其实这样的话,封装就有意义了,多次调用同一方法肯定比多个不同方法要快)

    这里解释一下isa,imp指针:
    isa:

    是类指针,之所以说isa是指针是因为Class其实是一个指向objc_class结构体的指针,而isa 是它唯一的私有成员变量,即所有对象都有isa指针(isa位置在成员变量第一个位置)

    说一下对 isa 指针的理解, 对象的isa 指针指向哪里?isa 指针有哪两种类型?

    isa 等价于 is kind of

    实例对象(instance) isa 指向类对象
    类对象指 isa 向元类对象
    元类对象的 isa 指向元类的基类
    isa 有两种类型:纯指针,指向内存地址

    Root class(class)其实就是NSObject,NSObject是没有超类的,所以Root class(class)的Superclass指向nil;
    每个Class都有一个isa指针指向唯一的meta class;
    Root class(meta)的Superclass指向Root class(class),也就是NSObject,形成一个回路;
    每个meta class的isa指针都指向Root class(meta)。(结合图)

    IMP :(Implementation缩写)

    (1)它是指向一个方法具体实现的指针,每一个方法都有一个对应的IMP。(可以直接调用方法的IMP指针,来避免方法调用死循环的问题)
    (2)当你发起一个 ObjC 消息之后,最终它会执行的那段代码,就是由IMP这个函数指针指向了这个方法实现的。

    sel:

    方法名称的描述,只记录方法的编号不记录具体的方法,具体的方法是 IMP

    3,转发

    如果上述都没找到,则进入消息转发

    〇,动态方法解析

    resolveInstanceMethod(实例方法),resolveClassMethod(类方法)

    解释:在此处可以添加一个方法,让你有机会添加,如果不抓住,就进入快速消息转发

    ①,快速消息转发
    forvardingTargetForSelector

    解释:这里指定对象执行什么方法,如果指定对象的方法没有实现也会崩溃,如果没指定,则返回nil,到2

    ②,正常消息转发
    methodSignatureForSelector,forwardInvocation

    解释:返回方法签名,下一步,返回nil未处理到forwardInvocation( 通过anInvocation处理)
    判断当前执行的方法签名是否存在,存在则交给父类处理,不存在,则手动注册一个方法签名,当返回注册的新方法签名后,马上就会开始执行forwardInvocation,forwardInvocation里面可以没操作,但必须实现forwardInvocation方法

    ③,崩溃:doesnotrecognaziedselector

    4,应用

    ①,获取类的所有属性和方法(获取后改变其属性方法,比如最左侧边滑动返回改为全屏返回)
    ②,为类添加关联属性(extension中,比如uiviewcontroller添加一个加载动画,uiview添加手势点击及事件回调)
    ③,为类动态添加方法,消息转发里面该写
    ④,方法交换(改变加载顺序,将load和init改变顺序,使得显示更加迅速)
    ⑤,给按钮添加间隔点击,方法交换

    5,swift使用

    Swift代码中已经没有了Objective-C的运行时消息机制, 在代码编译时即确定了其实际调用的方法. 所以纯粹的Swift类和对象没有办法使用runtime, 更不存在method swizzling.

    为了兼容Objective-C, 凡是继承NSObject的类都会保留其动态性, 依然遵循Objective-C的运行时消息机制, 因此可以通过runtime获取其属性和方法, 实现method swizzling.

    对于基本框架如Foundation, UIKit等, 都可以使用runtime.

    ①这里, 要注意Swift的代码与Objective-C代码的语法区别:

    同时, 对于一般OC代码的method swizzling, 在load方法中执行即可. 而Swift没有load, 所以要在initialize中执行.

    ②Swift中的@objc和dynamic关键字:

    继承自NSObject的类都遵循runtime, 那么纯粹的Swift类呢?
    在属性和方法之前加上@objc关键字, 则一般情况下可以在runtime中使用了. 但有一些情况下, Swift会做静态优化而无法使用runtime.
    要想完全使得属性和方法被动态调用, 必须使用dynamic关键字. 而dynamic关键字会隐式地加上@objc来修饰.
    获取Swift类的runtime信息的方法, 还要加上Swift模块名。

    附加面试题:runtime 如何实现 weak 属性?

    首先要搞清楚weak属性的特点:

    weak策略表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,

    设置方法既不保留新值,也不释放旧值。此特质同assign类似;然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)

    那么runtime如何实现weak变量的自动置nil?

    runtime对注册的类,会进行布局,会将 weak 对象放入一个 hash 表中。用 weak 指向的对象内存地址作为 key,

    当此对象的引用计数为0的时候会调用对象的 dealloc 方法,假设 weak 指向的对象内存地址是a,那么就会以a为key,

    在这个 weak hash表中搜索,找到所有以a为key的 weak 对象,从而设置为 nil。

    weak属性需要在dealloc中置nil么?

    在ARC环境无论是强指针还是弱指针都无需在 dealloc 设置为 nil , ARC 会自动帮我们处理。

    即便是编译器不帮我们做这些,weak也不需要在dealloc中置nil。

    在属性所指的对象遭到摧毁时,属性值也会清空

    相关文章

      网友评论

          本文标题:iOS Runtime!!!

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