有人能解释一下NSRunLoop
是什么吗?我知道NSRunLoop
是与NSThread
相关的东西,对吗?所以假设我创建了一个线程
NSThread* th=[[NSThread alloc] initWithTarget:self selector:@selector(someMethod) object:nil];
[th start];
-(void) someMethod
{
NSLog(@"operation");
}
所以在这个线程完成他的工作后,对吗?为什么使用RunLoops
或在哪里使用?从苹果文档中我读到了一些东西,但对我来说不清楚,所以请尽可能简单地解释
6条答案
按热度按时间g0czyy6m1#
运行循环是一种抽象概念,它提供了一种处理系统输入源(套接字、端口、文件、键盘、鼠标、计时器等)的机制。
每个NSThread都有自己的运行循环,可以通过currentRunLoop方法访问该循环。
一般来说,您不需要直接访问运行循环,尽管有一些(网络)组件可以允许您指定它们将使用哪个运行循环来进行I/O处理。
给定线程的运行循环将等待,直到它的一个或多个输入源具有一些数据或事件,然后激发适当的输入处理程序来处理每个"就绪"的输入源。
在这样做之后,它将返回到它的循环,处理来自各种源的输入,如果没有工作要做,则"休眠"。
这是一个相当高层次的描述(试图避免太多的细节)。
我试图回应这条评论。我把它分成了几部分。
事实上,. NSRunLoop不是线程安全的,只能从运行该循环的线程的上下文访问。
如果您想监控某个端口,只需将该端口添加到run循环中,然后run循环将监视该端口的活动。
也可以使用显式添加计时器
run循环将在每次迭代中处理所有ready事件(根据其模式)。您需要查看文档来了解运行模式,因为这超出了一般答案的范围。
在大多数应用程序中,主运行循环将自动运行。然而,您需要负责启动运行循环并响应您旋转的线程的传入事件。
我不明白你在这里的意思。你不向run循环添加事件。你添加输入源和计时器源(来自拥有run循环的线程)。run循环然后监视它们的活动。当然,你可以从其他线程和进程提供数据输入,但是输入将由run循环处理,该run循环监视运行run循环的线程上的那些源。
事实上,一个run循环会"停留"在一个事件处理程序中,直到该事件处理程序返回。你可以在任何应用程序中看到这一点。为任何休眠的IO操作(例如,按钮按下)安装一个处理程序。你将阻塞主run循环(和整个UI),直到该方法完成。
这同样适用于任何运行循环。
我建议您阅读以下关于运行循环的文档:
https://developer.apple.com/documentation/foundation/nsrunloop
以及它们在线程中的使用方式:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1
wkftcu5l2#
运行循环将*交互式应用与命令行工具区分开来。
从here开始
它们允许你等待用户点击并做出相应的响应,等待你得到一个completionHandler并应用它的结果,等待你得到一个计时器并执行一个函数。如果你没有一个runloop,你就不能监听/等待用户点击,你不能等待一个网络呼叫发生,你不能在x分钟内被唤醒,除非你使用
DispatchSourceTimer
或DispatchWorkItem
也来自这条评论:
后台线程没有自己的runloop,但是你可以添加一个。例如AFNetworking 2.x就做了。这是NSURLConnection或NSTimer在后台线程上使用过的可靠技术,但是我们自己不再这么做了,因为更新的API消除了这样做的需要。但是看起来URLSession做了,例如here is simple request,在主队列上运行[见图片左侧面板]完成处理程序,您可以看到它在后台线程上有一个run循环
具体涉及:"后台线程没有自己的runloops"。以下计时器无法为async调度激发:
我认为
sync
块也运行的原因是:为了测试,我在每个派遣中都记录了
RunLoop.current
。同步调度具有与主队列相同的runloop。而异步块中的RunLoop是与其他示例不同的示例。您可能会想为什么
RunLoop.current
返回不同的值。它不是 * shared * 值吗!?好问题!请进一步阅读:current
不是全局变量。返回当前线程的运行循环。
它是上下文相关的。它只在线程即Thread-local storage的作用域中可见。更多信息请参见here。
这是定时器的已知问题。如果使用
DispatchSourceTimer
,则不会出现相同的问题qyswt5oh3#
RunLoops有点像一个盒子,事情就这样发生了。
基本上,在RunLoop中,你去处理一些事件然后返回。或者如果在超时之前它没有处理任何事件就返回。你可以说它类似于异步NSURLConnections,在后台处理数据而不干扰你当前的循环,但同时,你需要数据同步。这可以在RunLoop的帮助下完成,它使你的异步
NSURLConnection
并在调用时提供数据。你可以像这样使用RunLoop:在此RunLoop中,它将一直运行,直到您完成了其他一些工作并将YourBoolFlag设置为false。
同样,您可以在线程中使用它们。
希望这对你有帮助。
nkoocmlb4#
运行循环是与线程关联的基本基础结构的一部分。运行循环是一种事件处理循环,用于调度工作和协调传入事件的接收。运行循环的目的是在有工作要做时使线程保持忙碌状态,在没有工作要做时使线程休眠。
从这里
CFRunLoop最重要的特性是CFRunLoopModes。CFRunLoop与"运行循环源"系统一起工作。源在运行循环上注册为一个或多个模式,并且运行循环本身在给定模式下运行。当事件到达源时,如果源模式与运行循环当前模式匹配,则仅由运行循环处理。
从这里
jqjz2hbq5#
运行循环是一种事件处理循环,用于连续监视和处理输入事件,并将它们分配给相应的目标进行处理。
r55awzrz6#
RunLoop(EventLoop, Looper)
是EventLoop(事件处理循环)模式的实现。它基于NSRunLoop
(CFRunLoopRef
的 Package 器)Official doc
运行循环是与线程关联的基本基础结构的一部分。运行循环是一种事件处理循环,用于调度工作和协调传入事件的接收。运行循环的目的是在有工作要做时使线程保持忙碌状态,在没有工作要做时使线程休眠。
单个线程可以在单个模式中具有单个RunLoop。只有具有此模式的事件才会被处理,所有其他事件都将等待RunLoop在该模式下启动
RunLoop是一种机制(基于循环(for,while)),它将计划任务(例如回调队列)移动到线程(线程堆栈)。RunLoop在线程堆栈为空时工作(
event processing loop
)。event processing loop
是在.entry
和.exit
之间运行循环的时间。在此期间,RunLoop以特定模式处理所有计划任务。所有其他模式及其自己的队列将在默认情况下,应用程序具有
main thread
和RunLoop(main loop)
。在其他情况下,应手动创建main run loop
负责清空应用程序中的main queue
。运行循环模式是要监视的输入源和计时器的集合以及要通知的运行循环观察器的集合。
模式:
scrollViewDidScroll
时<custom>
-您可以创建自己的模式例如:
UIView.draw(_ rect:)
,按钮操作...使用default mode
default mode
DispatchQueue.main.async
使用common mode
Timer.scheduledTimer
使用default mode
。这就是为什么当UI滚动发生时(在跟踪模式下),计时器不会触发(在默认模式下)。要修复此问题,请使用通用模式-RunLoop.main.add(timer, forMode: .common)
RunLoop.main
与DispatchQueue.main
(.receive(on:, options:)
)。RunLoop. main使用RunLoop.perform(_:)
,后者使用default mode
,DispatchQueue. main使用DispatchQueue.main.async
,后者使用common mode
运行循环接收事件:
Input sources
-异步事件(触发时)消息performSelector: onThread
Timer sources
-同步事件(在特定时间)计时器它们可以添加到多种模式
监视RunLoop的状态更改
创建新线程,设置RunLoop并启动线程
1.创建运行循环运行循环. current
1.运行循环必须至少有一个输入源或计时器才能监视RunLoop。add(_timer:定时器,用于Mode模式:运行循环.模式)运行循环.添加(_a端口:端口,用于Mode模式:运行循环模式)
1.运行运行循环www.example.com() RunLoop.run ()