runloop的学习总结

上传人:第*** 文档编号:31079293 上传时间:2018-02-04 格式:DOC 页数:16 大小:149KB
返回 下载 相关 举报
runloop的学习总结_第1页
第1页 / 共16页
runloop的学习总结_第2页
第2页 / 共16页
runloop的学习总结_第3页
第3页 / 共16页
runloop的学习总结_第4页
第4页 / 共16页
runloop的学习总结_第5页
第5页 / 共16页
点击查看更多>>
资源描述

《runloop的学习总结》由会员分享,可在线阅读,更多相关《runloop的学习总结(16页珍藏版)》请在金锄头文库上搜索。

1、RunLoop 的学习总结一. RunLoop 相关概念1. 什么是 RunLoopRunLoop 与线程相关且是基础框架的一部分。一个 RunLoop 就代表一个事件处理循环,它可以不停的调度工作以及处理输入事件。使用 RunLoop 的目的是有效的控制线程的执行和休眠,让线程在有工作的时候忙于工作,而在没工作的时候处于休眠状态。如果不使用RunLoop 类似的循环机制,线程执行完当前任务队列中的任务就结束了,程序不能持续运行。也可以把 RunLoop 理解成一个高级的死循环,这个死循环可以让程序持续运行,且可以时刻监听和处理各种事件。每一个线程都有唯一对应的 RunLoop,主线程的 Ru

2、nLoop 是默认开启的;子线程的RunLoop 要显示开启且至少添加一个事件源 source。我们不需要显示的创建 RunLoop,因为 RunLoop 是懒加载的,在 Cocoa 和 Core Fundation 中都提供了关于 RunLoop 对象的API 来帮助配置和管理线程对应的 RunLoop。2. RunLoop 的简单剖析下图是 RunLoop 与 Source 的联系图,图中的左边方框代表一个线程,线程的开始 Start 到结束 End 之间有一个 RunLoop,当这个 RunLoop 一直存在的时候,线程就不会销毁。方框中黄色的圈圈代表一个 RunLoop,圈圈左边代表当

3、有事件源时,RunLoop 就会被唤醒( 线程也随之被唤醒),RunLoop 会先检测定时事件源,再检测关于 performSelector:onThread:的事件源,再检测自定义事件源,最后检测基于端口的事件源。圈圈右边代表当没有事件源时,RunLoop 和线程都处于睡眠状态。当然 RunLoop 也可以通过 runUntilDate:方法设定过期时间来退出,当时间到的时候,RunLoop 退出,线程也随之销毁。图中的右边代表事件源的类型,它们分别是:基于端口的事件源、自定义事件源、关于performSelector:onThread:的事件源、定时事件源,前三种又统称为输入事件源。只有当

4、RunLoop 存在时,才能保证这些事件源能被处理;如果 RunLoop 不存在,当前线程运行到End 时,线程就会被销毁了,之后如果再有事件源尝试在这个线程中处理事件,系统就会崩溃报错。RunLoop 与 Source 的联系示意图:提示:输入事件源传递异步事件,通常消息来自于其它线程或程序;定时事件源传递同步事件,事件发生在特定时间或者重复的时间间隔。RunLoop 会在处理事件之前发出通知,但要监听这些通知,必须注册一个观察者 observer添加到 RunLoop 中才可监听。3. RunLoop 的运行模式一个 RunLoop 要能运行,必须要有一个运行模式。 RunLoop 的一个

5、运行模式是所有要监听的输入源、定时源、观察者的集合。当要运行一个 RunLoop 时,必须指定(无论显示还是隐式指定)一个运行模式。在 RunLoop 的运行过程中,只有和模式相关的输入源和定时源才会被处理,只有和模式相关的观察者才会被激活。和其它运行模式相关的输入源、定时源、观察者,只有在其相关的模式下才能被运行,否则处于暂停状态。通过指定 RunLoop的运行模式可以使得 RunLoop 在某一阶段过滤来源于源的事件。大多数时候,RunLoop 都是运行在系统定义的默认模式上。CFRunLoopModeRef 对象代表 RunLoop 的一个运行模式,一个 Runloop 对象可以有多个运

6、行模式,但至少有一个运行模式,每个运行模式内又包含若干个 Source/Timer/Observer,运行模式内的 Source/Timer/Observer 可以没有,但是如果没有,RunLoop 对象运行时就直接退出了。当要切换运行模式时,必须先停止当前的运行模式,才能启动新的运行模式,这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。系统默认注册的 5 个运行模式:NSDefaultRunLoopMode:App 的默认 Mode,通常主线程是在这个 Mode 下运行UITrackingRunLoopMode:界面跟踪 Mode,用于 Scroll

7、View 追踪触摸滑动,保证界面滑动时不受其他 Mode 的影响UIInitializationRunLoopMode: 刚启动 App 时进入的第一个 Mode,启动完成后就不再使用,开发中一般不用GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到提示: 在 Core Foundation 的底层有一个 mutable set 类型的集合 Common Modes,集合中保存着NSDefaultRunLoopMode 和 UITrackingRunLoopMode,NSRunLoopCommonModes 是用来标记它们的,只要使用了 NSRunL

8、oopCommonModes,就相当于同时使用NSDefaultRunLoopMode 和 UITrackingRunLoopMode4. Source 的分类按照官方文档:a. 基于端口的输入事件源 b. 自定义输入事件源 c. Cocoa 关于 performSelector 的事件源 d. 定时事件源按照函数调用栈:a. Source0:非基于 Port 的源 b. Source1:基于 Port 的源,通过内核和其他线程通信,能接收和分发系统的事件 c. 定时事件源5. 输入事件源输入源异步的发送消息给你的线程。事件来源可以分为两种:基于端口的输入源和自定义输入源。基于端口的输入源监听

9、程序相应的端口。自定义输入源则监听自定义的事件源。RunLoop 不关心输入源的是基于端口还是自定义的。两类输入源的区别在于是谁发送: 基于端口的输入源由内核自动发送,而自定义的输入源则需要人工从其他线程发送。创建好了事件源,还需要把事件源分配给 RunLoop 的一个或多个运行模式,当 RunLoop 运行在被添加到的运行模式时,事件源才会被监听到。基于端口的输入事件源 Cocoa 和 Core Foundation 支持与端口相关的对象和函数,用它们来创建的基于端口的源。在 Cocoa 中不需要直接创建输入源,只要简单地创建端口对象,并使用 NSPort 的方法把该端口添加到 RunLoo

10、p 中,端口对象会自己创建和配置输入源,基于端口的事件源处理完后不会自动从 RunLoop 中移除。在 Core Foundation 中,必须人工创建端口和它的事件源,可以使用端口相关的函数(CFMachPortRef,CFMessagePortRef,CFSocketRef) 来创建相关对象。void createPortSource() / 创建消息端口CFMessagePortRef messagePort = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR(com.someport),myCallbackFunc, NULL,

11、NULL);/ 创建自定义基于端口的源CFRunLoopSourceRef sourcePort = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, messagePort, 0);/ 把自定义基于端口的源加入 RunLoopCFRunLoopAddSource(CFRunLoopGetCurrent(), sourcePort, kCFRunLoopCommonModes);/ 运行 RunLoopCFRunLoopRun();/ RunLoop 退出后移除自定义基于端口的源CFRunLoopRemoveSource(CFRunLo

12、opGetCurrent(), source, kCFRunLoopDefaultMode);/ 撤销引用CFRelease(source);自定义输入事件源 要创建自定义输入源,只能使用 Core Foundation 里面与 CFRunLoopSourceRef 类型相关的函数来创建。可以使用回调函数来配置自定义输入源,当 Core Fundation 配置源时,会在多处地方调用回调函数,处理输入事件,当事件源被移除的时要清理它。除了定义自定义输入源的行为,还要定义消息传递机制;事件源的消息传递在线程里面实现,并负责在数据等待处理的时候传递数据给事件源并通知它处理数据;消息传递机制的定义逻

13、辑取是随意的,但最好不要过于复杂。void createCustomSource() / 定义自定义输入源的上下文CFRunLoopSourceContext context = 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL;/ 创建自定义输入源CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, / 把自定义输入源加入 RunLoopCFRunLoopAddSource(CFRunLoopGetCurrent(), source, k

14、CFRunLoopDefaultMode);/ 运行 RunLoopCFRunLoopRun();/ RunLoop 退出后移除自定义输入源CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);/ 撤销引用CFRelease(source);Cocoa 关于 performSelector 的事件源 在 Cocoa 中,可以使用关于 performSelector 的方法自定义事件源,一个 selector 执行完后会自动从 RunLoop 里面移除。关于 performSelector:onTh

15、read:的方法,目标线程要有一个活动的 RunLoop,否则系统可能崩溃,因为目标线程可能已经被销毁。当目标线程是非主线程时,要显示开启 RunLoop,才能保证程序正常执行。关于performSelector:afterDelay:的方法,也需要有一个活动的 RunLoop,因为它会自动创建一个 NSTimer 对象加入当前的 RunLoop,如果在子线程中使用,需要手动启动 RunLoop,事件才会被处理。/ 在主线程中执行 selectorperformSelectorOnMainThread:withObject:waitUntilDone:performSelectorOnMain

16、Thread:withObject:waitUntilDone:modes:/ 在指定线程中执行 selector/ 目标线程必须要有一个活动的 RunLoop,否则可能崩溃,因为目标线程可能已经被销毁performSelector:onThread:withObject:waitUntilDone:performSelector:onThread:withObject:waitUntilDone:modes:/ 在当前线程执行 selector,可设置延迟时间/ 会自动创建一个 NSTimer 对象加入当前的 RunLoop,如果在子线程中使用,需要手动启动 RunLoop,事件才会被处理performSelector:withObject:afterDelay:performSelector:withObject:afterDelay:inModes:/ 在当前线程执行 selectorperformSelector:performSelector:withObject:perf

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号