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

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

MethodsDescription

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.

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.

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.

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结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/260013.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android播放flv,Android:从url播放flv视频流

我目前有一个应用程序,它可以记录视频并将其上传到我的服务器。在上传视频之后,应用程序会获得一个响应,该响应包含指向该文件的flv流的URL。Android:从url播放flv视频流当我尝试在android默认视频播放器(视频)中打开流时什么也没…

1.关于浏览器

一、认识主流浏览器 Chrome谷歌浏览器Safari苹果浏览器Firefox火狐浏览器Opera欧朋浏览器 二、浏览器内核是什么? 三、五大浏览器,四大内核 四、前端做网页开发用什么浏览器? Chrome谷歌浏览器。

About me [my way]

就要除夕了。假日的到来,心情瞬间就闲适了下来。早早上了床,看看电脑还有30%的电,想到一些事情,顺带纪录一下吧。 今年坚持上班到了除夕的前一天,爸妈来工作的城市陪我过年了。感谢他们。前几天就已经看帖子有说仍在上…

明天要中秋节了,先来到简单“类”的题目

2-1 Point类的定义 Time Limit: 1000MS Memory limit: 65536K 题目描述 通过本题目的练习可以掌握类与对象的定义; 设计一个点类Time,它具有私有数据成员x(横坐标)、y(纵坐标);公有成员函数:SetPoint(int,int)用于设置点对象的值&…

实时数据交换平台 - BottledWater-pg with confluent

标签 PostgreSQL , Bottled Water , Kafka , Confluent , IoT 背景 想必大家都在图书馆借过书,小时候有好看的书也会在小伙伴之间传阅。 借书和数据泵有点类似,一份数据通过数据泵实时的分享给订阅者。 例如在IoT的场景中,有流式分析的需求&a…

科技鸿蒙系统一千章,第一千六百零七章 鸿蒙紫气,成圣之机 (上)

文学迷 > 玄幻魔法 > 天命神相 > 第一千六百零七章 鸿蒙紫气,成圣之机 (上)第一千六百零七章 鸿蒙紫气,成圣之机功德金身只要达到了八十一重天,大圆满的境界,实力堪混元大罗级别的圣人,这听起来确实是一件吊炸…

js reduce实现中间件_js数组高阶方法reduce经典用法代码分享

以下是个人在工作中收藏总结的一些关于javascript数组方法reduce的相关代码片段,后续遇到其他使用这个函数的场景,将会陆续添加,这里作为备忘。javascript数组那么多方法,为什么我要单挑reduce方法,一个原因是我对这个…

struts2的s:iterator 标签 详解

struts2的s:iterator 可以遍历 数据栈里面的任何数组,集合等等 以下几个简单的demo:s:iterator 标签有3个属性: value:被迭代的集合 id :指定集合里面的元素的id status 迭代元素的索引1:jsp…

Protocol Buffers的应用

1. Protocol Buffers的介绍 Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then …

编程提高:一天一道编程题

1.文本操作 逆转字符串——输入一个字符串,将其逆转并输出。 拉丁猪文字游戏——这是一个英语语言游戏。基本规则是将一个英语单词的第一个辅音音素的字母移动到词尾并且加上后缀-ay(譬如“banana”会变成“anana-bay”)。可以在维基百科上了…

android自验签名证书,没有以前的互联网连接,无法验证Android自签名证书

使用SSL基础架构:我们有一个有效的客户端/服务器设置,其中Android版本4.2和4.4的手机充当客户端,必须通过其自签名SSL证书验证服务器.问题:只要设备在尝试连接之前至少有一次互联网访问权限,服务器证书验证就会起作用.但是,如果执行恢复出厂设置且设备直…

asp.net缓存(二)

ASP.NET页面局部缓存 有时缓存整个页面是不现实的,因为页的某些部分可能在每次请求时都需要变化。在这些情况下,只能缓存页的一部分。顾名思义,页面部分缓存是将页面部分内容保存在内存中以便响应用户请求,而页面其他部分内容则为…

学习C# - Hello,World!

第一天学C#,开始学着写一些学习笔记,看了一下传智播客的视频,按照传智播客的教学顺序,开始学习。 class Program{static void Main(string[] args){Console.WriteLine("Hello World!");//自动添加回车换行Console.Write("Hell…

android获取button宽度,android – 如何获得Button的高度和宽度

我创建了一系列按钮.现在我想找到按钮的高度和宽度,为此我使用了getWidth()和getHeight().但问题是它总是返回0.为什么会发生这种情况?我发送了我的代码,请检查是否有任何问题.int x,y;LinearLayout layoutVertical (LinearLayout) findViewById(R.id.liVLayout);L…

java执行sql列名无效_嵌套异常是java.sql.SQLException:无效的列名ORACLE

我尝试在Java中使用JdbcTemplate执行以下oracle查询:select RESOURCE_IDfrom REPRO_PRINTING_JOBwhere (USER_ID? and PRINTING_CENTER_ID?)group by RESOURCE_IDunion allselect RESOURCE_IDfrom REPRO_PRINTING_JOB_OLDwhere (USER_ID? and PRINTING_CENTER_ID…

(七)Maven使用的最佳实践

这里说一下在使用Maven过程中不是必须的,但十分有用的几个实践,关键时刻或许能解决您的问题。 1.设置MAVEN_OPTS环境变量 通常需要设置MAVEN_OPTS的值为-Xms128m -Xmx512m,因为Java默认的最大可用内存往往不能够满足Maven运行的需要&#xff…

android beam传输速率,无线网络的速率为何不能达到最大值

1、无线速率可以达到最大值,只是发送速率和传输流量是两个概念,通俗点讲,无线的发送速率是把信号以指定速率发出去(信号好的时候以高速率发,信号差的时候以低速率发)。传输流量是指单位时间内传输的数据量,大部分用户关…

【SMTP 补录 Apache服务】

【补录,续】1.【配置空壳邮件接受】【mta】【前置:在/etc/named.rfc1912.zones 添加一个可以接受邮件的域hxl.org(与你数据库中写的向对应),这个域的所在ip就是你机子的,因为要从你的机子转发】 【配置该机的vim/etc/…

image打开rgb16 qt_QT中显示图像数据

一般图像数据都是以RGBRGBRGB……字节流的方式(解码完成后的原始图像流),我说成字节流,那就表明R,G,B的值各占一个字节,在编程时表示的就是unsigned char * data。我们先来看一下QT中的QImage对象。在加载data数据前&a…

开启chrome默认支持ipv6

在快捷方式后面的属性后面输入 --enable-ipv6 以下为转载: [转载]chrome开启或关闭IPV6方法 (2012-05-27 17:54:06) 转载▼ 标签: 转载 分类: 技术 原文地址:chrome开启或关闭IPV6方法作者:余鲲涛 chrome和firefox都是…