第9章:RunLoop面试问题

一、概念

     1、什么是RunLoop?

RunLoop是通过内部维护的事件循环来对事件/消息进行管理的一个对象。

     2、什么是事件循环?

没有消息需要处理时,休眠以避免资源占用,此时当前线程的控制权由用户态切换到内核态;有消息需要处理时,立即被唤醒,此时状态由内核态切换到用户态。

     3、应用程序的main函数为什么能一直运行不退出?

因为main函数中调用了UIApplicationMain函数,UIApplicationMain中启动了RunLoop循环。

 

二、数据结构

     对RunLoop的数据结构深入了解后才能对RunLoop的事件循环机制更好的理解。

     NSRunLoop是对CFRunLoop的封装,提供了面向对象的API。下面我们使用苹果的http://opensource.apple.com/tarballs/CF/CF-855.17.tar.gz源码来分析CFRunLoop。

     RunLoop的数据结构主要有三个:CFRunLoop、CFRunLoopMode、Source/Timer/Observer

     CFRunLoop的主要成员为pthread、currentMode、modes、commonModes、commonModeItems。pthread代表线程,RunLoop和线程是一一对应的关系;currentMode是CFRunLoopMode这个数据结构的对象;modes是NSMutableSet<CFRunLoopMode*>这么一个集合;commonModes是NSMutableSet<NSString*>这么一个集合,存储CommonMode映射的mode,将事件添加到CommonMode时会将事件添加到该集合的所有mode中,具体源码参考“RunLoop与NSTimer”章节;commonModeItems是包含Observer、Timer、Source对象的集合,存储被添加到CommonMode中的事件源,具体源码参考“RunLoop与NSTimer”章节。

     CFRunLoopMode的主要成员为name、sources0、sources1、observers、timers。name是字符串类型,就是CFRunLoopMode对象的名称,如NSDefaultRunLoopMode。sources0、sources1是MutableSet类型,是无序的。observers、timers是MutableArray类型,是有序的。

     CFRunLoopSource分两种:source0、source1。source0需要手动唤醒线程,source1具备唤醒线程的能力。source0使用时,你需要先调用 CFRunLoopSourceSignal(source),将这个 Source 标记为待处理,然后手动调用 CFRunLoopWakeUp(runloop) 来唤醒 RunLoop,让其处理这个事件。注意:timer和source1(也就是基于port的source)可以反复使用,比如timer设置为repeat,port可以持续接收消息,而source0在一次触发后就会被runloop移除。

     CFRunLoopTimer是基于事件的定时器,它和NSTimer是可以toll-free bridged(免费桥转换)的。

     CFRunLoopObserver用于观测CFRunLoop的时间点,有6个:kCFRunLoopEntry(即将进入Loop)、kCFRunLoopBeforeTimers(即将处理 Timer)、kCFRunLoopBeforeSources(即将处理 Source )、kCFRunLoopBeforeWaiting(即将进入休眠 )、kCFRunLoopAfterWaiting(刚从休眠中唤醒)、kCFRunLoopExit(即将退出Loop)。

 

三、CFRunLoop各数据结构之间的关系

     作者说这很能体现开发者对RunLoop的理解深度,用于区分开发者的级别。

     RunLoop和线程是一对一的关系,和mode是一对多的关系。而mode和Source/Timer/Observer也是一对多的关系。如下图

     1、如何将事件同时加入两个mode?

此时需要用到NSRunLoopCommonModes,它并不是一个实际存在的模式,他是同步Source/Timer/Observer到多个mode中的一种技术解决方案。

 

四、事件循环机制

     NSRunLoop和CFRunLoop的run相关方法最终都会调用CFRunLoop 的void CFRunLoopRun()函数。

     Runloop是基于pthread进行管理的,pthread是基于c的跨平台多线程操作底层API。它是mach thread的上层封装(可以参见Kernel Programming Guide),和NSThread一一对应(而NSThread是一套面向对象的API,所以在iOS开发中我们也几乎不用直接使用pthread)。

 

五、RunLoop与NSTimer

     1、滑动TableView的时候我们的定时器还会生效吗?

不会生效,因为滑动TableView时RunLoop工作的mode发生了切换。此时需要调用void CFRunLoopAddTimer(runLoop, timer, commonMode)将timer添加到NSRunLoopCommonModes下,该方法的源码如下:

 

六、RunLoop与多线程

     线程和RunLoop是一一对应的。自己创建的线程默认是没有启动RunLoop的。

     1、怎样实现一个常驻线程?

1)、为当前线程开启一个RunLoop。

2)、向该RunLoop中添加一个Port/Source等维持RunLoop的事件循环。

3)、启动该RunLoop。

     2、常驻线程实现代码

     3、怎样保证子线程数据回来更新UI的时候不打断用户的滑动操作?

封装一个事件,将事件添加到主线程的defaultMode中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值