run loop 再次理解和总结

run loop是什么?

RunLoop 的本质就是一个函数,其内部是一个 do-while 循环。
线程需要调用runloop这个函数,来处理传入的事件。线程会一直停留在这个循环里;直到超时或被手动停止,该函数才会返回。

run loop的功能

处理事件,包括由输入源传来的事件,和定时器传来的事件。
产生有关运行行为的notifications。可以在线程中给runloop添加监听者。
run loop循环都在干些什么,看下图,建议就大概看看留个印象就好,然后继续往下看。
这里写图片描述

run loop Mode是什么?

run loop Mode,运行模式,是一组事件源集合和一组监听者集合。这里所说的事件源是事件的来源,不是事件本身。
运行run loop的时候需要显式或隐式地指定运行模式。runloop只会处理与当前运行模式相关的事件源传来的事件,只会通知与当前运行模式相关的监听者。此时,与当前运行模式不相关的事件发生后需要等待,直到run loop切换到与其关联的模式才能被执行。
我们可以往run loop的某一个运行模式中添加事件源和监听着。
模式有哪些?对应的名称及使用场景是什么?

1、四个常规模式

(1)默认模式 NSDefaultRunLoopMode 大多数操作在该模式下完成,建议在该模式下启动runloop,以及配置输入源。
(2)连接模式 NSConnectionReplyMode Cocoa用这种模式来和NSConnection对象一起监视连接响应。不建议使用这个模式。
(3)模态模式 NSModalPanelRunLoopMode Cocoa使用这个模式来标识意图模态面板的事件。
(4)事件追踪模式 NSEventTrackingRunLoopMode 在鼠标拖拽等用户交互过程中,Cocoa使用这个模式对输入事件进行限制。

2、一个特殊模式

普通模式 NSRunLoopCommonModes 普通模式是以上模式中常用的几个模式的集合,默认情况下包括默认模式,模态模式和事件追踪模式。这个普通模式存在的意义在于它的同步功能。同步功能是指,可以将任意模式添加到这个普通模式中,然后只要将事件源或者监听者添加到这个普通模式中,就相当于添加(同步)到了普通模式中包含的各个模式中。也就是说,这个普通模式只是一个概念,一个标识,并不是一个真正的模式,run loop不会以普通模式运行,只会运行在以上的常规模式。

产生事件的两个源头

下面分别介绍产生事件的两个源头,一个是输入源,一个是定时器。

1、输入源

输入源分三类,一种是基于端口的输入源,一种是自定义的输入源,一种是来自Cocoa层的输入源。
(1)基于端口的输入源
要新建基于端口的输入源会用到Cocoa 层的NSPort,或者Core Foundation中的CFMachPortRef、CFMessagePortRef、CFSocketRef。这里不多说。
(2)自定义的输入源
要新建自定义的输入源需要用到CFRunLoopSource。这里也不多说。
(3)来自Cocoa层的输入源
要创建来自Cocoa层的输入源,系统已经提供了几个方法,就在NSObject中定义,方法名以performSelector开头。使用这几个方法,只要我们提供需要执行的selector,就可以为我们创建输入源(实际上也是自定义输入源),并为我们添加到指定的线程当中,在线程中被串行地执行的,并且在执行完毕后,输入源会自动从run loop中移除。需要注意的是,这一切正常发生的前提是,事件源所添加到的目标线程,需要有一个正在运行的run loop。换句话说,一个线程只能对应一个run loop,但线程创建之后,run loop还没有在运行(run loop函数还没有被调用),因此往往需要显式地启动该线程的runloop(调用run loop函数)。唯一一个不需要手动启动的runloop是主线程对应的runloop,它在程序启动的时候就启动了,只要程序启动完毕就可以使用这个runloop了。runloop会在一次循环中处理完所有排着队的输入源的selector,而不是每次执行一个selector,直到处理完毕。

2、定时器

定时器产生的事件,就是定时器所设定的启动时间到达,run loop处理这个事件的实际就是执行定时器所绑定的selector。定时器在创建的时候需要指定它要加入的运行模式,就是run loop mode。将定时器加入到run loop之后,要等到这个run loop运行在定时器创建时指定的运行模式,这个定时器才会被启动。如果定时器加入到run loop的时候,这个run loop正好处在合适的运行模式,但是正在处理其他事件,那么run loop会在下一次循环时再启动这个定时器。当然,可以将定时器加入到普通模式,NSRunLoopCommonModes中,也就相当于将定时器加入到了多个模式中,那么不论run loop正运行在普通模式中的哪一个模式,定时器的事件都能得到处理。不过,和上面第(2)、(3)种输入源一样,这一切的前提是线程已经进入了run loop循环。那么,说了那么多,有些操作就变得很有用了,比如获取当前线程的run loop,启动run loop等。这些在下面继续讲。

使用run loop

上面说到run loop本质上是一个函数,函数内部是一个do-while循环,但它也有相关的属性,比如运行模式等,也有启动和停止的需求,因此它被封装成了CFRunLoop,其指针类型为CFRunLoopRef。NSRunloop是对CFRunLoop进行了进一步的封装。下面就介绍操作run loop的方法(针对CFRunLoop和NSRunloop的方法都有)。
1、获取当前线程的runloop:
需要获取线程a的runloop需要在线程a中调用以下方法。
方法一:[NSRunloop currentRunloop];
方法二:CFRunLoopGetCurrent(void);
2、开启runloop:
方法一:无条件开启,即调用run方法。
方法二:设定runloop开启时间
3、结束runloop
方法一:设定runloop的失效时间
方法二:直接停止runloop,调用CFRunLoopStop();

以上内容,参考了苹果官网的Thread Programming Guide,以及一个大神的博客,好崇拜Ta。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值