了解NSRunLoop

问题描述 投票:98回答:4

任何人都可以解释NSRunLoop是什么吗?所以我知道NSRunLoopNSThread有关吗?因此,假设我创建了一个类似于

的线程
NSThread* th=[[NSThread alloc] initWithTarget:self selector:@selector(someMethod) object:nil];
[th start];

-(void) someMethod
{
    NSLog(@"operation");
}

因此,在此主题完成工作后,正确吗?为什么使用RunLoops或在哪里使用?从苹果文档中我读了一些东西,但对我来说还不清楚,所以请尽可能简单地解释一下

ios objective-c cocoa-touch nsrunloop
4个回答
190
投票

运行循环是(除其他外)提供一种处理系统输入源(套接字,端口,文件,键盘,鼠标,计时器等)的机制的抽象。

每个NSThread都有自己的运行循环,可以通过currentRunLoop方法进行访问。

[通常,您不需要直接访问运行循环,尽管有些(网络)组件可以允许您指定它们将用于I / O处理的运行循环。

给定线程的运行循环将等待,直到其一个或多个输入源具有某些数据或事件,然后触发适当的输入处理程序以处理每个“就绪”的输入源。

[这样做之后,它将返回其循环,处理来自各种来源的输入,如果没有工作要做,则“睡眠”。

这是一个相当高级的描述(试图避免过多的细节)。

编辑

尝试发表评论。我把它弄碎了。

  • 这意味着我只能访问/运行线程内的运行循环对吧?

的确。 NSRunLoop不是线程安全的,只能从运行循环的线程的上下文中进行访问。

  • 有没有简单的示例如何添加事件以运行循环?

如果要监视端口,只需将该端口添加到运行循环中,然后运行循环将监视该端口的活动。

- (void)addPort:(NSPort *)aPort forMode:(NSString *)mode

您还可以通过以下方式显式添加计时器

- (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
  • 这意味着它将随后返回其循环吗?

运行循环将在每次迭代时(根据其模式)处理所有就绪事件。您将需要查看文档以发现有关运行模式的信息,因为这超出了常规答案的范围。

  • 启动线程时,运行循环是否处于非活动状态?

在大多数应用程序中,主运行循环将自动运行。但是,您有责任启动运行循环并响应所旋转线程的传入事件。

  • 是否可以在线程外的线程运行循环中添加一些事件?

我不确定您的意思。您不将事件添加到运行循环中。您添加输入源和计时器源(从拥有运行循环的线程中)。然后,运行循环监视它们的活动。当然,您可以提供来自其他线程和进程的数据输入,但是输入将由监视正在运行运行循环的线程上的那些源的运行循环进行处理。

  • 这是否意味着有时候我可以使用运行循环来阻止线程一段时间

的确。实际上,运行循环将“停留”在事件处理程序中,直到该事件处理程序返回为止。您可以在任何应用程序中简单地看到它。为任何休眠的IO操作(例如,按下按钮)安装处理程序。您将阻塞主运行循环(和整个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


8
投票

RunLoops有点像刚发生事情的盒子。

基本上,在RunLoop中,您要处理一些事件,然后返回。如果超时之前未处理任何事件,则返回。您可以说它类似于异步NSURLConnections,它在后台处理数据而不干扰您的当前循环,但同时您需要同步数据。可以在RunLoop的帮助下完成,RunLoop使您的异步NSURLConnection并在调用时提供数据。您可以像这样使用RunLoop:

NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];

while (YourBoolFlag && [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:loopUntil]) {
    loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];
}

在此RunLoop中,它将运行直到完成其他一些工作并将YourBoolFlag设置为false

类似地,您可以在线程中使用它们。

希望对您有帮助。


3
投票

运行循环是分离 交互式应用程序的来源命令行工具。

  • 使用参数启动命令行工具,执行其命令,然后退出。
  • 交互式应用程序wait供用户输入,做出反应,然后恢复等待。

来自here

它们允许您等到用户轻按并做出相应的响应,等到您获得completeHandler并应用其结果,再等到您获得计时器并执行功能。如果没有运行循环,则无法监听/等待用户敲击,也不能等到网络通话发生,否则无法在x分钟内唤醒,除非使用DispatchSourceTimer或[ C0]

也来自DispatchWorkItem

背景线程没有自己的运行循环,但是您可以添加一。例如。 this comment做到了。经过尝试和真正的技术NSURLConnection或NSTimer在后台线程上,但是我们不这样做随着更新的API消除了这样做的麻烦,我们自己也变得更多了。但似乎URLSession确实在运行[例如C0] [请参见图像的左侧面板]主队列上的完成处理程序,您可以看到它已运行在后台线程上循环


特别是关于:“背景线程没有自己的运行循环”。以下计时器无法触发async调度:

AFNetworking 2.x

我认为here is simple request块也运行的原因是:

sync块通常只是从其source队列中执行。在此示例中,源队列是主队列,whatever队列是目标队列。

以测试我在每次调度中都记录了class T { var timer: Timer? func fireWithoutAnyQueue() { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in print("without any queue") // success. It's being ran on main thread, since playgrounds begin running from main thread }) } func fireFromQueueAsnyc() { let queue = DispatchQueue(label: "whatever") queue.async { self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in print("from a queue — async") // failed to print }) } } func fireFromQueueSnyc() { let queue = DispatchQueue(label: "whatever") queue.sync { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in print("from a queue — sync") // success. Weird. Read my possible explanation below }) } } func fireFromMain() { DispatchQueue.main.async { self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in print("from main queue — sync") //success }) } } }

同步调度具有same运行循环作为主队列。异步块中的RunLoop是与其他实例不同的实例。您可能在想为什么sync返回不同的值。它不是shared值。好问题!进一步阅读:

重要提示:

class属性 RunLoop.current不是全局变量。

返回当前线程的运行循环。

它是上下文的,即仅在线程范围内,即RunLoop.current可见)。有关更多信息,请参见current

这是计时器的已知问题。如果您使用current

,则不会有相同的问题

0
投票

运行循环是与线程相关的基础结构的一部分。运行循环是事件处理循环,可用于安排工作并协调收到的事件的接收。运行循环的目的是在有工作要做时让线程忙,而在没有工作时让线程进入睡眠状态。

Thread-local storage


CFRunLoop的最重要功能是CFRunLoopModes。 CFRunLoop与“运行循环源”系统一起使用。源在一种或几种模式的运行循环中注册,并且使运行循环本身以给定模式运行。当事件到达源时,只有源模式与运行循环当前模式匹配时,运行循环才处理该事件。

here

© www.soinside.com 2019 - 2024. All rights reserved.