基础总结(runtime/runloop)

1.runtime介绍(https://www.jianshu.com/p/ea2d0a6fa8d6)

OC是一门动态语言,所以它总想办法把一些决定工作从编译推迟到运行时。也就是说只有编译器是不够的,它还需要一个运行时系统来执行编译后的代码。这就是Runtime系统存在的意义,它是整个OC的一个基石。

Runtime基本是用C和汇编语言写的,可见苹果为动态系统的高效做出的努力。

Runtime库主要做下面几件事:

封装:在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。

runtime核心是消息传递;

1. 消息发送流程

   确定调用方法的类是否加载完毕

   调用objc_msgSend方法,给调用对象发送消息

   对象在方法缓存列表(cache)中查询是否有对应方法,有直接调用

   没有的话在对象方法列表中查找->父类->>>nsobject 没找到进入消息动态解析

2. 消息动态解析

   接收消息对象未找到对应的实现方法,调用solverStanceMethod或者solverClassMethod 看是否进行方法动态创建方法 创建了就直接使用再次进入消息发送流程没有就进入消息转发

接收消息对象未找到对应的实现方法,调用solverStanceMethod后者solverClassMethod看是否进行方法动态创建方法 创建了就直接使用再次进入

3. 消息转发

   快速转发:forwardingTargertSelector方法进行方法执行对象重定向这个快速转发方法,没有处理就进入完整消息转发 调用methodSignatureForSelector获得函数的参数和返回值类型 创建nsinvocation(求助对象)  发送forwardingInvocation消息给目标对象 没获取到函数信息  就会发出 donsNotrecognizeselector消息 崩溃

应用

1.    动态方法交换 method  swizzling

        通过 class_getClassMethod()/Class_getInStanceMethod()方法,获取方法实现地址,通过method_exhangeImplementtations()方法交换两个方法

       方法的置换在类的 +load方法中调用

       拦截并替换系统方法

2.    分类添加新属性 

借助runtime的关联对象特性,帮助我们在运行阶段任意属性关联到一个对象上,实现属性一样的效果;

      例子:  nsdate分类的year/month/day/hour等

3.    获取类的详细信息

包裹属性列表/成员变量/方法/协议等

 4. 动态添加方法和修改属性变量的值

 5. 归档和解档  字典和模型的转换(KVC)

6.    KVO实现原理

利用Runtime生成一个中间对象,让原对象的isa指针指向它,然后重写 setter方法,插入willChangeValueForKey和didChangeValueForKey方 法。 当属 性变化时会调用,会调用这两个方法通知到外界属性变化。


runloop

它是一个处理事件的循环(线程进入这个循环,运行事件处理程序来响应传入的事件),RunLoop的目的是当有事件需要处理时,线程是活跃的、忙碌的,当没有事件后,线程进入休眠

Runloop Mode实际上是 Source,Timer 和 Observer 的集合,不同的 Mode 把不同组的Source,Timer和Observer隔绝开来.Runloop 在某个时刻只能跑在一个 Mode 下,处理这一个 Mode 当中的 Source,Timer 和 Observer

基本作用

1、保持程序的持续运行

2、处理App中的各种事件(比如触摸事件、定时器事件等)

3、节省CPU资源,提高程序性能:该做事时做事,该休息时休息

应用范畴

1、定时器(Timer)、PerformSelector

2、GCD Async Main Queue

3、事件响应、手势识别、界面刷新

4、网络请求

5、AutoreleasePool

runloop与线程之间的关系

1、每条线程都有唯一的一个与之对应的RunLoop对象

2、RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value

3、线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建([NSRunLoop currentRunLoop])

4、RunLoop会在线程结束时销毁

5、主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop

runloop内部实现逻辑

第一步:首先通知Observers进入Loop 然后处理一些 定时器、事件、block

第二步:事件处理完成之后通知Observers进入休眠状态开始休眠 等待消息唤醒

第三步:通知Observers结束休眠处理一些 定时器、事件、block

autoreleasePool 在何时被释放

App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()

第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池,优先级最高,保证创建释放池发生在其他所有回调之前

第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池,优先级最低,保证其释放池子发生在其他所有回调之后

在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了

PerformSelector 的实现原理

当调用NSObject的performSelecter:afterDelay:后,实际上其内部会创建一个Timer并添加到当前线程的RunLoop中,所以如果当前线程没有RunLoop,则这个方法会失效

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容