ios 理解 NSRunLoop
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12091212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Understanding NSRunLoop
提问by taffarel
Can anyone explain for what is NSRunLoop
? so as I know NSRunLoop
is a something connected with NSThread
right? So assume I create a Thread like
谁能解释一下是NSRunLoop
什么?所以据我所知NSRunLoop
是与NSThread
正确的东西有关吗?所以假设我创建了一个线程
NSThread* th=[[NSThread alloc] initWithTarget:self selector:@selector(someMethod) object:nil];
[th start];
-(void) someMethod
{
NSLog(@"operation");
}
so after this Thread finishes his working right? why use RunLoops
or where to use ? from Apple docs I have read something but its not clear for me, so please explain as simple as it possible
所以在这个线程完成他的工作之后呢?为什么使用RunLoops
或在哪里使用?从 Apple 文档我读过一些东西,但对我来说不清楚,所以请尽可能简单地解释
回答by Jody Hagins
A run loop is an abstraction that (among other things) provides a mechanism to handle system input sources (sockets, ports, files, keyboard, mouse, timers, etc).
运行循环是一种抽象(除其他外)提供处理系统输入源(套接字、端口、文件、键盘、鼠标、计时器等)的机制。
Each NSThread has its own run loop, which can be accessed via the currentRunLoop method.
每个 NSThread 都有自己的运行循环,可以通过 currentRunLoop 方法访问。
In general, you do not need to access the run loop directly, though there are some (networking) components that may allow you to specify which run loop they will use for I/O processing.
通常,您不需要直接访问运行循环,尽管有一些(网络)组件可能允许您指定它们将用于 I/O 处理的运行循环。
A run loop for a given thread will wait until one or more of its input sources has some data or event, then fire the appropriate input handler(s) to process each input source that is "ready.".
给定线程的运行循环将等待,直到它的一个或多个输入源有一些数据或事件,然后触发适当的输入处理程序来处理每个“就绪”的输入源。
After doing so, it will then return to its loop, processing input from various sources, and "sleeping" if there is no work to do.
这样做之后,它将返回到它的循环,处理来自各种来源的输入,如果没有工作要做,则“休眠”。
That's a pretty high level description (trying to avoid too many details).
这是一个非常高级的描述(试图避免太多细节)。
EDIT
编辑
An attempt to address the comment. I broke it into pieces.
试图解决评论。我把它掰成碎片。
- it means that i can only access/run to run loop inside the thread right?
- 这意味着我只能访问/运行以在线程内运行循环,对吗?
Indeed. NSRunLoop is not thread safe, and should only be accessed from the context of the thread that is running the loop.
的确。NSRunLoop 不是线程安全的,只能从运行循环的线程的上下文中访问。
- is there any simple example how to add event to run loop?
- 有没有简单的例子如何向运行循环添加事件?
If you want to monitor a port, you would just add that port to the run loop, and then the run loop would watch that port for activity.
如果要监视端口,只需将该端口添加到运行循环中,然后运行循环将监视该端口的活动。
- (void)addPort:(NSPort *)aPort forMode:(NSString *)mode
You can also add a timer explicitly with
您还可以使用显式添加计时器
- (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
- what means it will then return to its loop?
- 什么意味着它将返回到它的循环?
The run loop will process all ready events each iteration (according to its mode). You will need to look at the documentation to discover about run modes, as that's a bit beyond the scope of a general answer.
运行循环将在每次迭代中处理所有就绪事件(根据其模式)。您需要查看文档以了解运行模式,因为这有点超出一般答案的范围。
- is run loop inactive when i start the thread?
- 当我启动线程时运行循环是否处于非活动状态?
In most applications, the main run loop will run automatically. However, you are responsible for starting the run loop and responding to incoming events for threads you spin.
在大多数应用程序中,主运行循环将自动运行。但是,您负责启动运行循环并响应您旋转的线程的传入事件。
- is it possible to add some events to Thread run loop outside the thread?
- 是否可以向线程外的线程运行循环添加一些事件?
I am not sure what you mean here. You don't add events to the run loop. You add input sources and timer sources (from the thread that owns the run loop). The run loop then watches them for activity. You can, of course, provide data input from other threads and processes, but input will be processed by the run loop that is monitoring those sources on the thread that is running the run loop.
我不确定你在这里的意思。您不会向运行循环添加事件。您添加输入源和计时器源(来自拥有运行循环的线程)。然后运行循环监视它们的活动。当然,您可以提供来自其他线程和进程的数据输入,但输入将由运行循环处理,该运行循环正在运行运行循环的线程上监视这些源。
- does it mean that sometimes i can use run loop to block thread for a time
- 这是否意味着有时我可以使用运行循环来阻塞线程一段时间
Indeed. In fact, a run loop will "stay" in an event handler until that event handler has returned. You can see this in any app simply enough. Install a handler for any IO action (e.g., button press) that sleeps. You will block the main run loop (and the whole UI) until that method completes.
的确。实际上,运行循环将“停留”在事件处理程序中,直到该事件处理程序返回为止。您可以在任何应用程序中轻松地看到这一点。为任何休眠的 IO 操作(例如,按下按钮)安装处理程序。您将阻塞主运行循环(和整个 UI),直到该方法完成。
The same applies to any run loop.
这同样适用于任何运行循环。
I suggest you read the following documentation on run loops:
我建议您阅读以下有关运行循环的文档:
https://developer.apple.com/documentation/foundation/nsrunloop
https://developer.apple.com/documentation/foundation/nsrunloop
and how they are used within threads:
以及它们如何在线程中使用:
回答by Honey
Run loops are what separatesinteractiveapps from command-linetools.
- Command-line tools are launched with parameters, execute their command, then exit.
- Interactive apps waitfor user input, react, then resume waiting.
From here
运行循环将交互式应用程序与命令行工具区分开来 。
- 命令行工具使用参数启动,执行它们的命令,然后退出。
- 交互式应用程序等待用户输入,做出反应,然后继续等待。
从这里
They allow you to wait till user taps and respond accordingly, wait till you get a completionHandler and apply its results, wait till you get a timer and perform a function. If you don't have a runloop then you can't be listening/waiting for user taps, you can't wait till a network call is happening, you can't be awoken in x minutes unless you use DispatchSourceTimer
or DispatchWorkItem
它们允许您等到用户点击并做出相应响应,等到您获得 completionHandler 并应用其结果,等到您获得计时器并执行功能。如果你没有运行循环,那么你就不能监听/等待用户点击,你不能等到网络呼叫发生,你不能在 x 分钟内被唤醒,除非你使用DispatchSourceTimer
或DispatchWorkItem
Also from this comment:
同样来自此评论:
Background threads don't have their own runloops, but you can just add one. E.g. AFNetworking 2.xdid it. It was tried and true technique for NSURLConnection or NSTimer on background threads, but we don't do this ourselves much anymore, as newer APIs eliminate the need to do so. But it appears that URLSession does, e.g., here is simple request, running [see the left panel of the image] completion handlers on the main queue, and you can see it has a run loop on background thread
后台线程没有自己的运行循环,但您可以添加一个。例如AFNetworking 2.x做到了。对于后台线程上的 NSURLConnection 或 NSTimer 来说,这是一种久经考验的技术,但我们自己不再这样做了,因为较新的 API 消除了这样做的需要。但似乎 URLSession 确实如此,例如,这里是简单的 request,在主队列上运行 [见图像的左侧面板] 完成处理程序,您可以看到它在后台线程上有一个运行循环
Specifically about: "Background threads don't have their own runloops". The following timer fails to fire for an asyncdispatch:
具体来说:“后台线程没有自己的运行循环”。以下计时器无法为异步调度触发:
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
})
}
}
}
I think the reason the sync
block also runs is because:
我认为该sync
块也运行的原因是:
syncblocks usually just get executed from within their sourcequeue. In this example, source queue is main queue, the whateverqueue is the destination queue.
同步块通常只是从它们的源队列中执行。在这个例子中,源队列是主队列,whatever队列是目标队列。
To test that I logged RunLoop.current
inside every dispatch.
为了测试我是否登录了RunLoop.current
每次派遣。
The sync dispatch had the samerunloop as main queue. While the RunLoop within the async block was a different instance from the others. You might be thinking how why does RunLoop.current
return a different value. Isn't it a sharedvalue!? Great question! Read further:
同步调度与主队列具有相同的运行循环。而异步块中的 RunLoop 是与其他实例不同的实例。您可能在想为什么RunLoop.current
返回不同的值。这不是共享价值吗!?好问题!进一步阅读:
IMPORTANT NOTE:
重要的提示:
The class propertycurrent
is NOT a global variable.
在类属性current
不是一个全局变量。
Returns the run loop for the currentthread.
返回当前线程的运行循环。
It's contextual. It's visible only within the scope of the thread ie Thread-local storage. For more on that see here.
这是上下文。它仅在线程范围内可见,即Thread-local storage。有关更多信息,请参见此处。
This is a known issue with timers. You don't have the same issue if you use DispatchSourceTimer
这是计时器的已知问题。如果您使用,则不会遇到相同的问题DispatchSourceTimer
回答by Akshay Sunderwani
RunLoops are a bit of like a box where stuff just happens.
RunLoops 有点像一个盒子,事情就在那里发生。
Basically, in a RunLoop, you go to process some events and then return. Or return if it doesn't process any events before the timeout is hit.
You can say it as similar to asynchronous NSURLConnections, Processing data in the background without interfering your current loop and but at the same time, you require data synchronously.
Which can be done with the help of RunLoop which makes your asynchronous NSURLConnection
and provides data at calling time.
You can use a RunLoop like this:
基本上,在 RunLoop 中,你去处理一些事件然后返回。或者如果它在超时之前不处理任何事件,则返回。你可以说它类似于异步 NSURLConnections,在不干扰当前循环的情况下在后台处理数据,但同时,你需要同步数据。这可以在 RunLoop 的帮助下完成,它使您的异步NSURLConnection
并在调用时提供数据。您可以像这样使用 RunLoop:
NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];
while (YourBoolFlag && [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:loopUntil]) {
loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];
}
In this RunLoop, it will run until you complete some of your other work and set YourBoolFlagto false.
在这个 RunLoop 中,它会一直运行,直到您完成其他一些工作并将YourBoolFlag设置为false。
Similarly, you can use them in threads.
同样,您可以在线程中使用它们。
Hope this helps you.
希望这对你有帮助。
回答by dengApro
Run loops are part of the fundamental infrastructure associated with threads. A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.
运行循环是与线程相关的基础架构的一部分。运行循环是一个事件处理循环,您可以使用它来安排工作和协调传入事件的接收。运行循环的目的是在有工作要做的时候让你的线程保持忙碌,在没有工作时让你的线程休眠。
The most important feature of CFRunLoop is the CFRunLoopModes. CFRunLoop works with a system of “Run Loop Sources”. Sources are registered on a run loop for one or several modes, and the run loop itself is made to run in a given mode. When an event arrives on a source, it is only handled by the run loop if the source mode matches the run loop current mode.
CFRunLoop 最重要的特性是 CFRunLoopModes。CFRunLoop 与“Run Loop Sources”系统一起工作。源在一个或多个模式的运行循环上注册,并且运行循环本身在给定的模式下运行。当事件到达源时,如果源模式与运行循环当前模式匹配,则仅由运行循环处理。