iOS消息循环-模式匹配

以下内容均来自互联网,但属于个人摘录总结,主要分析一下“只有当消息循环的模式与事件模式匹配时,消息循环才会运行”这句话的模式匹配,是哪些模式匹配哪些模式。

每个线程都有一个消息循环,主线程消息循环默认开启,子线程消息循环默认都是关闭的,需要手动开启。消息循环与线程之间是一一对应的关系,其关系保存在一个全局字典里面(字典的key为线程,value为消息循环)。

你只能在线程结束时销毁消息循环。除了主线程即UI线程,你只能在线程内部获取消息循环。

为消息循环添加事件,事件有两种类型:

  • 输入源:异步传递事件,通常是来自不同的线程或不同的应用的消息。输入源异步传递事件到对应的处理程序和在线程关联的NSRunLoop对象调起runUntilDate:方法来退出事件处理。
  • 定时源:同步地传递事件,发生在每个定时器调用或周期性地调用。Timer源传递事件到他们的处理程序,但是不会调用run loop来退出处理。

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

[self demo];

}

-(void) demo{

NSTimer* timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(task) userInfo:nil repeats:YES];//创建定时源 指定定时源执行的方法

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

//将该定时源加入到当前线程下的消息循环中,指定消息循环模式为NSRunLoopCommanModes

}

-(void) task{

NSLog(@"%@",[[NSRunLoop currentRunLoop] currentMode]);  //输出当前消息循环的模式

NSLog(@"我是输入事件的定时源指定的执行方法");

}

注意上面代码中,[[NSRunLoop currentRunLoop] currentMode]是指当前消息循环的模式,而消息循环模式是输入源和定时源的一个集合,这个集合会被监听.

每次启动运行循环,可以指定一个特殊的模式,在运行循环执行期间,只有跟特定的模式相关联的事件源才会被监听以及允许传递它们的事件,跟其它模式相关联的事件源将不会被监听。

上述代码执行结果

我在故事板中添加了一个textView,上述代码中指定的消息循环模式为NSRunLoopCommanModes。拖动textView时消息循环模式为UITrackingRunLoopMode,松开后为KCFRunLoopDefaultMode,事件发生改变,对应消息循环模式也发生了改变。

iOS消息循环的两个对象是NSRunLoop和CFRunLoop,前者是对后者的封装。

CFRunLoop是Core Foundation框架里的对象,提供了纯c API,所有API是线程安全的。

NSRunLoop是Cocoa框架里的对象,是对CFRunLoop的封装,API不是线程安全的。

以下是系统定义的几种消息循环模式

Mode Name Description
Default
NSDefaultRunLoopMode(Cocoa)

kCFRunLoopDefaultMode (Core Foundation)


可以用于大多数操作。在大多数时间,应该使用这种模式来启动和设置输入源。

Connection NSConnectionReplyMode(Cocoa) Cocoa使用这种模式联合NSConnection对象来监听响应。我们很少会自己用到这种模式
Modal NSModalPanelRunLoopMode(Cocoa) Cocoa使用这种模式来识别为模态面板准备的事件。
Event tracking NSEventTrackingRunLoopMode(Cocoa)  Cocoa使用这种模式来约束鼠标拖拽或其它用户界面追踪循环的事件。
Common modes
NSRunLoopCommonModes(Cocoa)

kCFRunLoopCommonModes (Core Foundation)

这是一个通用的模式组,使用这种模式关联输入源,同样会关联这个模式组里面的每一种模式。对于Cocoa应用来说,这个集合包含了 default、modal以及event tracking模式。

Core Foundation初始状态下只包含 default 模式,但是可以通过 CFRunLoopAddCommonMode函数来添加自定义模式。

模式 目的 普通模式的一部分?
kCFRunLoopDefaultMode 默认的运行循环模式,几乎涵盖所有的来源。 你应该总是添加源和计时器这种模式下,如果没有特别的原因。 可以用符号kCFRunLoopDefaultModeNSDefaultRunLoopMode进行访问。
NSTaskDeathCheckMode 通过使用NSTask来检查任务仍在运行。
_kCFHostBlockingMode 
_kCFNetServiceMonitorBlockingMode 
_kCFNetServiceBrowserBlockingMode 
_kCFNetServiceBlockingMode 
_kCFStreamSocketReadPrivateMode 
_kCFStreamSocketCanReadPrivateMode 
_kCFStreamSocketWritePrivateMode 
_kCFStreamSocketCanWritePrivateMode 
_kCFStreamSocketSecurityClosePrivateMode 
_kCFStreamSocketBogusPrivateMode 
_kCFURLConnectionPrivateRunLoopMode 
_kProxySupportLoadingPacPrivateMode 
_kProxySupportSyncPACExecutionRunLoopMode
_kCFStreamSocketSecurityClosePrivateMode
使用各种私人运行的循环模式CFNetwork的阻止操作 没有
UITrackingRunLoopMode UI跟踪。
GSEventReceiveRunLoopMode 接收系统事件。 没有
com.apple.securityd.runloop 与securityd通信。 通过使用跳板而已。 没有
FigPlayerBlockingRunLoopMode QuickTime的关系。 没有

在上面提到的一段代码中,循环模式由kCFRunLoopDefaultMode变为UITrackingRunLoopMode,而对程序的输入源事件由默认变为“约束鼠标拖拽或其它用户界面追踪循环的事件”。那就这个例子来说 是不是说明默认事件(大多数操作事件)对应消息循环模式的kCFRunLoopDefaultMode,约束鼠标拖拽或其它用户界面追踪循环的事件对应循环模式的UITrackingRunLoopMode ?

那有没有人能告诉我,既然都是循环模式,执行NSLog(@"%@",[[NSRunLoop currentRunLoop] currentMode]); 为什么控制台输出的是第二个表格的kCFRunLoopDefaultMode和UITrackingRunLoopMode,而不是第一个表格的NSDefaultRunLoopMode和NSRunLoopCommonModes

我是菜鸟啊啊啊,如果知道请评论给我科普一下吧

时间: 2024-10-07 01:28:38

iOS消息循环-模式匹配的相关文章

IOS - RunLoop消息循环

什么是RunLoop? -RunLoop就是消息循环,每一个线程内部都有一个消息循环. -只有主线程的消息循环默认开启,子线程的消息循环默认不开启. RunLoop的目的 -保证程序不退出 . -负责处理输入事件.  -如果没有事件发生,会让程序进入休眠状态  . 事件类型 Input Sources (输入源) & Timer Sources (定时源) -输入源可以是键盘鼠标,NSPort, NSConnection 等对象,定时源是NSTimer 事件 添加消息到循环中 -创建输入源.(以

iOS中的消息循环

什么是消息循环: 消息循环就是NSRunloop这个类 ,每个线程都有自己的消息循环. 主线程的消息循环默认是开启的(需要去检测事件),子线程默认关闭(通常不需要子线程检测事件). 消息循环的目的: 保证程序不退出.负责处理输入事件(输入源和Timer源).如果没有事件发生则会让程序处于休眠状态. 消息循环的两种运行模式:NSDefaultRunloopModel和 NSRunloopCommonModels 消息循环需要在一定的模式下才能相匹配,当在消息循环中添加了一个定时源时, 消息循环的模

Android Handler 消息循环机制

前言 一问起Android应用程序的入口,很多人会说是Activity中的onCreate方法,也有人说是ActivityThread中的静态main方法.因为Java虚拟机在运行的时候会自动加载指定类的静态共有main方法,因此个人更倾向于第二种说法. public final class ActivityThread { ......  public static void main(String[] args) {  ......  Looper.prepareMainLooper(); 

IOS消息机制应用实例--异常处理

IOS消息机制应用实例--异常处理 最近发现了一个在项目中常用的异常处的工具NullSafe,分析了它的实现原理,不小心发现了一个小Bug,现将其分享出来,关于这篇文章的Demo已经上传至GitHub,看完如有收获,欢迎Star,如有疑问欢迎issue,大家一起学习.在IOS开发中我们可能会遇到下面的情景:服务器给我们返回得某个字段是null,比如someValue:null,这个时候我们利用第三方工具转化之后会得到someValue = <null>,这个时候如果我们判断这个someValu

QObject::deleteLater()并没有将对象立即销毁,而是向主消息循环发送了一个event,下一次主消息循环收到这个event之后才会销毁对象 good

程序编译运行过程很顺利,测试的时候也没发现什么问题.但后来我随手上传了一个1G大小的文件,发现每次文件上传到70%左右的时候程序就崩溃了,小文件就没这个问题.急忙打开任务管理器,这才发现上传文件的时候,程序内存占用会随着上传进度的增加而增加,上传1G文件的时候内存最多会吃到1.5G,这时候程序申请不到更多内存了,我又没做检查,当然就会崩溃掉. 限制上传文件大小这种事我是不会做的,毕竟一个上传工具占用内存比PS都高实在不科学.注意到文件上传完成之后内存会立即回到正常值,显然原因并不是我忘记释放内存

窗口创建及消息循环

窗口创建 1. 自定义窗口类别           WNDCLASS 2. 注册窗口类               RegisterClass 3. 创建窗口                 CreateWindow/CreateWindowEx                 WM_CREATE 4. 显示窗口                 ShowWindow                                  WM_SIZE & WM_SHOWWINDOW 5. 更新窗口 

WinMain初始化详细过程以及消息循环

主要内容:详细介绍WinMain函数的初始化过程以及消息循环 1.窗口类定义 通过给窗口类数据结构WNDCLASS赋值完成, 该数据结构中包含窗口类的各种属性 <1>LoadIcon 作用:在应用程序中加载一个窗口图标 原型:HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName) //第一个参数为图标资源所在的模块句柄, //指向用户所加载图标的那个窗口 //若为NULL则使用系统预定义图标 //第二个参数为图标资源名或系统预定义图标标识

MFC中PeekMessage的使用,非阻塞消息循环

在程序设计的时候经常要进行一个数据循环,比如播放音乐需要循环的向缓冲区里面写入数据,在这个时候比较通用的方法是建立一个线程做事情,但是有时候不想创建多线程就可以使用微软提供的PeekMessage方法,使用起来很简单,如下 while(waveOutUnprepareHeader((HWAVEOUT)hWaveOut, lpWaveHdr, sizeof(WAVEHDR))!= MMSYSERR_NOERROR) { //循环清除缓冲区,如果成功表示播放完毕 //如果没有播放完毕则循环下面语句

深入探讨MFC消息循环和消息泵

首先,应该清楚MFC的消息循环(::GetMessage,::PeekMessage),消息泵(CWinThread::PumpMessage)和MFC的消息在窗口之间的路由是两件不同的事情.在MFC的应用程序中(应用程序类基于CWinThread继承),必须要有一个消息循环,他的作用是从应用程序的消息队列中读取消息,并把它派送出去(::DispatchMessage).而消息路由是指消息派送出去之后,系统(USER32.DLL)把消息投递到哪个窗口,以及以后消息在窗口之间的传递是怎样的.  消