Run Loop

Run Loop就是一个事件处理的循环,用来不停的调动工作以及处理输入事件。使用Run Loop的目的就是节省CPU效率,线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。
一,Run Loop剖析
Structure of a Run Loop and its sources
上图显示了线程的输入源
A,基于端口的输入源(Port Sources)
B,自定义输入源(Custom Sources)
C,Cocoa执行Selector的源("performSelector...方法" Sources)
D,定时源(Timer Sources )
线程针对上面不同的输入源,有不同的处理机制
A,handlePort---处理基于端口的输入源
B,customSrc---处理用户自定义输入源
C,mySelector---处理Selector的源
D,timerFired---处理定时源
注:线程除了处理输入源,Run Loops也会生成关于Run Loop行为的通知(notification)。Run Loop观察者(Run-Loop Observers)可以收到这些通知,并在线程上面使用他们来作额为的处理
===在新线程的Run Loop中注册Observers:
---编写一个带有观测者的线程加载程序
- (void)observerRunLoop
{
// 建立自动释放池
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// 获得当前thread的Run loop
NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop];
// 设置Run Loop observer的运行环境
CFRunLoopObserverContext context = {0, self, NULL, NULL, NULL};
// 创建Run loop observer对象
// 第一个参数用于分配该observer对象的内存
// 第二个参数用以设置该observer所要关注的的事件,详见回调函数myRunLoopObserver中注释
// 第三个参数用于标识该observer是在第一次进入run loop时执行还是每次进入run loop处理时均执行
// 第四个参数用于设置该observer的优先级
// 第五个参数用于设置该observer的回调函数
// 第六个参数用于设置该observer的运行环境
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context);
if(observer)
{
// 将Cocoa的NSRunLoop类型转换程Core Foundation的CFRunLoopRef类型
CFRunLoopRef ç = [myRunLoop getCFRunLoop];
// 将新建的observer加入到当前的thread的run loop
CFRunLoopAddObserver(cfRunLoop, observer, kCFRunLoopDefaultMode);
}
// Creates and returns a new NSTimer object and schedules it on the current run loop in the default mode
[NSTimer scheduledTimerWithTImeInterval:0.1 target:self selector:@selector(doFireTimer:) userInfor:nil repeats:YES];
NSInteger = loopCount = 10;
do
{
// 启动当前thread的run loop直到所指定的时间到达,在run loop运行时,run loop会处理所有来自与该run loop联系的input sources的数据
// 对于本例与当前run loop联系的input source只有Timer类型的source
// 该Timer每隔0.1秒发送触发时间给run loop,run loop检测到该事件时会调用相应的处理方法(doFireTimer:)
// 由于在run loop添加了observer,且设置observer对所有的run loop行为感兴趣
// 当调用runUntilDate方法时,observer检测到run loop启动并进入循环,observer会调用其回调函数,第二个参数所传递的行为时kCFRunLoopEntry
// observer检测到run loop的其他行为并调用回调函数的操作与上面的描述相类似
[myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSiceNow:1.0]];
// 当run loop的运行时间到达时,会退出当前的run loop,observer同样会检测到run loop的退出行为,并调用其回调函数,第二个参数传递的行为是kCFRunLoopExit.
--loopCount;
}while(loopCount);
// 释放自动释放池
[pool release];
}
===observer的回调函数:
void myRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
switch(activity)
{
// The entrance of run loop, before entering the event processing loop.
// This activity occurs once for each call to CFRunLoopRun / CFRunLoopRunInMode
case kCFRunLoopEntry:
NSLog(@"run loop entry");
break;
// Inside the event processing loop before any timers are processed
case kCFRunLoopBeforeTimers:
NSLog(@"run loop before timers");
break;
// Inside the event processing loop before any sources are processed
case kCFRunLoopBeforeSources:
NSLog(@"run loop before sources");
break;
// Inside the event processing loop before the run loop sleeps, waiting for a source or timer to fire
// This activity does not occur if CFRunLoopRunInMode is called with a timeout of o seconds
// It also does not occur in a particular iteration of the event processing loop if a version 0 source fires
case kCFRunLoopBeforeWaiting:
NSLog(@"run loop before waiting");
break;
// Inside the event processing loop after the run loop wakes up, but before processing the event that woke it up
// This activity occurs only if the run loop did in fact go to sleep during the current loop
case kCFRunLoopAfterWaiting:
NSLog(@"run loop after waiting");
break;
// The exit of the run loop, after exiting the event processing loop
// This activity occurs once for each call to CFRunLoopRun and CFRunLoopRunInMode
case kCFRunLoopExit:
NSLog(@"run loop exit");
break;

/*
A combination of all the preceding stages
case kCFRunLoopAllActivities:
break;
*/
default:
break;
}
}
1,Run Loop模式---是所有要监测的输入源和定时源以及要通知的run loop注册观察者的集合。在run loop运行过程中,只有和模式相关的源才会被监测并允许他们传递事件消息。相反,没有被添加的输入源将会被过滤。
可以自定自己的Run Loop模式,但是每个模式必须有一个或者多个输入源,定时源或者run loop的观察者,否则,run loop直接退出,Run Loop模式将没有意义。
另,模式区分基于事件的源而非事件的种类。例如,不能使用模式只选择处理鼠标按下或者键盘事件。可以使用模式监听端口,而暂停定时器或者改变其他源或者当前模式下处于监听状态run loop观测着。

表1-1列出了cocoa和Core Foundation预先定义的模式。

2,Run Loop的输入源 
A,基于端口的输入源
通过内置的端口相关的对象和函数,创建配置基于端口的输入源。相关的端口函数---CFMachPort/CFMessagePortRef/CFSocketRf
B,自定义输入源
自定义输入源使用CFRunLoopSourceRef对象创建,它需要自定义自己的行为和消息传递机制
C,Cocoa执行Selector的源
和基于端口的源一样,执行Selector的请求会在目标线程上序列化,减缓在线程上允许许多各方法容易引起的同步问题。两者区别:一个Selector执行完成后会自动从Run Loop上移除。

Table:Performing selectors on other threads

Methods

Description

performSelectorOnMainThread:withObject:

waitUntilDone:

performSelectorOnMainThread:withObject:

waitUntilDone:modes:

Performs the specified selector on the

application’s main thread during that

thread’s next run loop cycle. These

methods give you the option of blocking

the current thread until the selector is

performed.

performSelector:onThread:withObject:waitUntilDone:

performSelector:onThread:withObject:

waitUntilDone:modes:

Performs the specified selector on any

thread for which you have an NSThread

object. These methods give you the

option of blocking the current thread

until the selector is performed.

performSelector:withObject:afterDelay:

performSelector:withObject:afterDelay:inModes:

Performs the specified selector on the

current thread during the next run loop

cycle and after an optional delay period.

Because it waits until the next run loop

cycle to perform the selector, these

methods provide an automatic mini

delay from the currently executing code.

Multiple queued selectors are performed

one after another in the order they were

queued.

cancelPreviousPerformRequestsWithTarget:

cancelPreviousPerformRequestsWithTarget:

selector:object:

Lets you cancel a message sent to the

current thread using theperformSelector:withObject:afterDelay:

orperformSelector:withObject:afterDelay:

inModes:method.

D,定时源
在预设的时间点同步方式传递消息,定时器是线程通知自己做某事的一种方法。
E,Run Loop观察者
源是合适的同步/异步事件发生时触发。观察者则是在Run Loop本身运行的特定时候触发。观察者触发的相关事件(参考上面红色程序里面的函数:myRunLoopObserves(...))
1)Run Loop入口
2)Run Loop何时处理一个定时器
3)Run Loop何时处理一个输入源
4)Run Loop何时进入休眠状态
5)Run Loop何时被唤醒,但在唤醒之前要处理的事件
6)Run Loop终止
注: 1,观察者通过CFRunLoopObserverRef对象创建的
2,观察者会在相应事件发生之前传递消息,所以通知的时间和事件实际发生的时间之间肯定有误差
F,Run Loop 的事件队列--包括观察者的事件队列
1)通知观察者Run Loop已经启动
2)通知观察者任何即将要开始的定时器
3)通知观察者任何即将启动的非基于端口的输入源
4)启动任何准备好的非基于端口的源
5)如果基于端口的源准备好了并处于等待状态,立即启动;并进入步骤9
6)通知观察者线程进入休眠
7)将线程置于休眠直到下面任一事件发生
A)某一事件到达基于端口的源
B)定时器启动
C)Run Loop设置的时间已经超时
D)Run Loop被显式唤醒
8)通知观察者线程被唤醒
9)处理未处理的事件
A)如果用户定义的定时器启动,处理定时器事件并重启Run Loop,进入步骤2
B)如果输入源启动,传递相应消息
C)如果Run Loop被显式唤醒而且时间还没有超时,重启Run Loop,进入步骤2
10)通知观察者Run Loop结束

转载于:https://www.cnblogs.com/luqinbin/p/5154206.html

iOS多线程开发(三)---Run Loop(一)相关推荐

  1. ios多线程开发的常用三种方式

    ios多线程开发的常用三种方式 1.NSThread 2.NSOperationQueue 3.GCD NSThread: 创建方式主要有两种: [NSThread detachNewThreadSe ...

  2. IOS多线程开发详解

    概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操 ...

  3. ios跨线程通知_iOS多线程编程指南(三)Run Loop

    Run loops是线程相关的的基础框架的一部分.一个run loop就是一个事件处理的循环,用来不停的调度工作以及处理输入事件.使用run loop的目的是让你的线程在有工作的时候忙于工作,而没工作 ...

  4. iOS多线程开发:几个容易被忽略的细节(马甲包)

    一般情况下,iOS开发者只要会使用GCD.@synchronized.NSLock等几个简单的API,就可以应对大部分多线程开发了,不过这样是否真正做到了多线程安全,又是否真正充分利用了多线程的效率优 ...

  5. iOS多线程开发:几个容易被忽略的细节

    一般情况下,iOS开发者只要会使用GCD.@synchronized.NSLock等几个简单的API,就可以应对大部分多线程开发了,不过这样是否真正做到了多线程安全,又是否真正充分利用了多线程的效率优 ...

  6. IOS多线程开发其实很简单

    http://blog.csdn.net/shenjie12345678/article/details/44152605 转载于:https://blog.51cto.com/8399249/165 ...

  7. iOS开发-多线程开发之线程安全篇

    前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象.同一个变量.同一个文件和同一个方法等.因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安 ...

  8. iOS多线程详解:实践篇

    iOS多线程实践中,常用的就是子线程执行耗时操作,然后回到主线程刷新UI.在iOS中每个进程启动后都会建立一个主线程(UI线程),这个线程是其他线程的父线程.由于在iOS中除了主线程,其他子线程是独立 ...

  9. ios跨线程通知_iOS多线程开发(三)---Run Loop(一)

    Run Loop Run Loop就是一个事件处理的循环,用来不停的调动工作以及处理输入事件.使用Run Loop的目的就是节省CPU效率,线程在有工作的时候忙于工作,而没工作的时候处于休眠状态. 一 ...

最新文章

  1. MultiObjective using Evolutionary Algorithms (2) -- Multi-Objective Optimization
  2. linux中find命令列举,Linux中常见find命令的使用
  3. 利用Sqoop将MySQL海量测试数据导入HDFS和HBase
  4. POJ - 1220 NUMBER BASE CONVERSION(高精度运算+进制转换+模拟)
  5. Java路径问题最终解决方案—可定位所有资源的相对路径寻址
  6. Linux下怎么创建和进入带有空格的文件夹
  7. thinkphp 助手函数url不生成https_如何用ThinkPHP框架写一个快递查询接口
  8. Doc2Bow简介与实践Demo
  9. 二级c语言笔试58,全国计算机等级考试-二级C语言笔试试题.doc
  10. java获取页面点击次数_java计算鼠标点击次数的题,急求!
  11. vba ado返回集合_利用VBA代码导出工作表中的图片
  12. 多线程java_由浅入深地介绍Java多线程,让你如何快速进入Java多线程的学习
  13. python识别中文中的名字地点时间_python中判断时间间隔的问题
  14. iOS设计模式之代理模式
  15. 基于STM32F405平台的多摩川协议编码器通讯过程(1)
  16. JAVAWEB-NOTE03
  17. 2018.09.02【BZOJ2227】【ZJOI2011】看电影 (高精度)(组合数)
  18. 第二人生的源码分析(12)天空显示的实现
  19. response.getStatusCode()==200什么意思
  20. dhtml gantt所有配置_dhtmlx-gantt相关配置

热门文章

  1. JZOJ 5415. 【NOIP2017提高A组集训10.22】公交运输
  2. Hdu 1754 . I Hate It
  3. JZOJ 1251. 收费站
  4. vs五子棋c语言代码,五子棋代码C语言版.doc
  5. pythonexcel表格教程_python对excel表格的操作
  6. 鸿蒙手机系统开发大会,鸿蒙OS+EMUI10,华为开发者大会的创新与看点
  7. 微软亚洲研究院发布“人立方关系搜索”
  8. NOIP2015年普级组试题 金币
  9. Codeforces 1188 题解
  10. BZOJ 2669 Luogu P3160 [CQOI2012]局部极小值 (容斥原理、DP)