iOS 关于RunLoop

一  runloop 解释

1. 运行循环(死循环).

2.负责处理监听事件 (如:触摸屏幕,时钟事件,网络事件等).

3.当没有事件可监听时,将处于休眠状态.

4.每一条线程都有一个runloop.(默认是不开启的)

5. - source(事件源source0:非内核事件由开发者产生如:点击屏幕触发事件,source1:系统内核事件由系统所产生. source0基于souce1,因为触摸屏幕等事件最终都会通知系统去处理)    - observe(runloop的观察者)   -  timer(时钟事件)

二  runloop 模式

总共五种模式

1. UITrackingRunLoopMode (UI模式,只能被UI事件触发 优先级非常高)

2.NSDefaultRunLoopMode (默认模式,处理时钟网络事件)

3.NSRunLoopCommonModes (占位模式,以上两种模式都添加)

4.App启动时第一个模式,runloop会处理启动事件,这个模式只运行一次(苹果不开放)

5.系统事件的内部模式(苹果不开放)

1. 在ViewController中添加一个NSTimer和一个UitableView. 运行发现时钟事件可以正常进行但如果我们拖动UITableView时时钟事件暂停.  

2. 此时我们在runloop默认模式下添加了一个timer每一秒就会通知runloop处理一次时钟事件,当我们拖动tableView时runloop会有优先处理UI模式下的事件所以造成时钟事件停顿(苹果默认UI处理事件优先保证UI流畅)

3. 如果我们将timer添加到UI处理模式下是不是就不会出现时钟暂停的情况了呢?(注意:上面timer的初始化方法不能被添加到runloop中)

运行发现只有在拖拽tableView时时钟事件才可以被触发,不拖拽时不会触发. 由于我们将timer添加到了UI处理模式下,这种模式下的runloop只能被UI处理事件唤醒,所以timer事件每一秒触发的事件不能唤醒runloop也就不会被执行

4. 此时我们将timer添加到占位模式下(占位模式就是默认模式及UI模式都有),发现默认及UI模式下时钟事件都可以被触发.

三 runloop与线程

1.  上面说过每一条线程里都会有一个runloop, 如果此时在时钟处理事件中添加一个耗时操作会发生什么呢?

发现两种模式下时钟事件都可以正常进行,但是拖拽tableVIew时会出现卡顿情况. 原因:主线程被阻塞了

2. 解决主线程被阻塞的办法通常是加一条子线程

创建一条子线程并将时钟事件添加进去,发现时钟事件并未被执行.原因thred的子线程在被执行一次后就被释放了,那么对thred进行强引用保证thred不被释放可以解决该问题吗?错!thred只是一个对象它的作用只是开起线程,而线程被释放与thred被不被释放无关,我们的runloop是添加在线程中的,线程走了runloop的存在就没有意义了所以时钟事件也就不会被执行了.

2.每个子线程里都有一个runloop只是默认不被开启的,那么我们现在将子线程中的runloop开启并把占位模式改成默认模式

发现时钟事件可以正常执行,但是'线程来了!!!!'这句代码没有被执行,原因runloop是一个运行循环它只会执行[[NSRunLoop currentRunLoop] run];这句代码上面的部分,下面的不会去执行.  此时存在两个runloop一个在主线程一个在子线程,拖动tableView也不会出现卡顿问题.

3. 此时由于子线程里面的runloop一直在运行循环,子线程变成了一个常驻线程,那么如何停止这个运行呢?

(1) 此时在子线程加一个while循环,手动设置runloop运行循环时间0.001s,当我们点击屏幕时runloop在执行最多0.001s后结束执行,子线程在执行完'线程来了!!!!!!!'这句代码后就被释放了不再是常驻线程. 时钟事件也就不再执行.(每条线程中都存在一个runloop当该线程中的runloop关闭后这条线程在执行完代码后就会被释放)

(2) 此时我们在点击屏幕时直接杀死时钟事件中的子线程, 子线程已经死了子线程中的runloop也就没有意义当然子线程中的代码'线程来了!!!!!!!'也不会再被执行.

(3)若此时我们在点击屏幕时杀死主线程,发现执行[NSThread exit];这段代码后的主线程中的'干掉了吗?'这句代码没有被执行,此时tableView也不能被拖动, 但是子线程中时钟事件依然被执行着.这说明子线程与主线程之间并不存在关系,只是因为苹果把UI处理事件都放在了主线程里,并且每个线程里都存在一个runloop当这个线程被干掉时它里面的runloop也就不再执行.

4. 现在通过GCD创建一个定时器

运行发现时钟事件可以正常进行,同时通过控制台打印日志可以看到GCD创建了多个线程来处理事件,由于GCD是创建在子线程的滑动UI也不会卡顿.GCD并不依赖runloop而是通过不停创建block线程实现计时功能.

四  runloop的监听者CFRunLoop

通常耗时操作都是放在子线程,UI操作放在主线程(UIkit框架是线程不安全的,如果加锁就会降低性能,苹果为了不让子线程抢夺主线程资源,所以规定UI操作统一放在主线程). 如果主线程出现耗时操作该怎么解决呢?

1. 如图 我们创建了一个tableView每个cell里面都做了移除又加载三张高清大图的操作.这一步渲染操作是比较耗时的,虽然模拟器可能不太明显但开发中应该会遇到过,当cell中加载内容过多时,tableView滑动起来会比较卡. 那是因为runloop在处理UI事件时由于图片渲染比较耗时runloop会一直处于等待状态,当所有内容渲染完毕后runloop才会继续运行循环(runLoop循环被卡住了).若此时一次展示n张图片runloop就要等这n张图片渲染完成后才会继续运行循环.在等待过程中我们拖动UI事件也不能被runloop处理.

2.  解决思路:让runloop每次循环只去渲染一张图片.  若想执行此操作首先我们就要监听到每次runloop的运行循环,这里就用到了runloop的监听者CFRunLoop 

能监听到的状态

typedefCF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {

    kCFRunLoopEntry = (1UL <<0), //runloop进入循环

    kCFRunLoopBeforeTimers = (1UL <<1),  //runloop处理Timers件前

    kCFRunLoopBeforeSources = (1UL <<2),//runloop处理Sources事件前

    kCFRunLoopBeforeWaiting = (1UL <<5),//runloop休眠前

    kCFRunLoopAfterWaiting = (1UL <<6),//runloop休眠后

    kCFRunLoopExit = (1UL <<7),//runloop退出

    kCFRunLoopAllActivities =0x0FFFFFFFU //所有事件

//由于是通过监听这些状态来发送通知的所以没有observer

};

 CFRunLoop是CoreFoundation框架下的所以创建都是用C语言写的,如图(上下文CFRunLoopObserverContext context是一个结构体,CFRetain和CFRelease可能指引用计数)我们在callback回调函数中监听到了runloop在等待之前的状态,我们只要在runloop处于这个状态的时候再去只加载一张图片就可以了

这里用到了block的方法.这里加载三张图片就创建了三个block,在block回调中去加载图片,然后依次将三个block放到一个数组中,然后在callback回调方法中依次取出block执行block回调操作,注意每执行完一个blok就要从数组中移除因为在这个block中已经加载了图片它的任务已经完成了然后才能依照代码从数组中取出下一个block执行加载图片操作.

按照上面的代码运行后发现滑动不再卡顿,但出现了一个bug. tableView刚加载时在滑动之前只显示已部分图片或者说只有在滑动时才会加载图片.那是因为只有在滑动触发UI事件时runloop才会执行,当我们停止滑动时此时runloop没有事件可执行就处于休眠状态了,我们也就监听不到runloop了进而也就不会执行加载图片的方法.解决办法很简单就是让runloop一直有事情做不让它处于休眠状态,如图添加一个时钟事件nstimer.这样我们就利用runloop成功优化了tableView滑动加载卡顿问题

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

推荐阅读更多精彩内容

  • 目录 Runloop RunLoop 与线程 个人理解总结 应用场景 1. 什么是RunLoop 基本作用 保持程...
    Ryan___阅读 1,560评论 0 13
  • 目录: App启动原理 RunLoop 的概念 RunLoop 与线程的关系 RunLoop 对外的接口 RunL...
    jiodg45阅读 898评论 0 6
  • 转自bireme,原地址:https://blog.ibireme.com/2015/05/18/runloop/...
    乜_啊_阅读 1,496评论 0 5
  • 深入理解RunLoop 由ibireme| 2015-05-18 |iOS,技术 RunLoop 是 iOS 和 ...
    橙娃阅读 910评论 1 2
  • 转自http://blog.ibireme.com/2015/05/18/runloop 深入理解RunLoop ...
    飘金阅读 1,022评论 0 4