【问题标题】:Why do I need an NSRunLoop to run a timer?为什么我需要一个 NSRunLoop 来运行计时器?
【发布时间】:2015-12-09 01:58:33
【问题描述】:

我购买了 Objective-C 的 Big Nerd Ranch 指南,关于 NSRunLoop 的内容我不知道。

这是书中的一段代码:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 
                                                  target:logger
                                                selector:@selector(updateLastTime:)
                                                userInfo:nil
                                                 repeats:YES];
[[NSRunLoop currentRunLoop] run];

我的问题是,为什么我需要为要处理的NSTimer 对象放置一个NSRunLoop?为什么它需要在结尾而不是开头?

为什么它不像其他函数或对象的方法,我只需要调用一个函数来处理它并登录到控制台?

我真的很想弄清楚这里每一个细节的每一个逻辑。

【问题讨论】:

标签: cocoa nstimer nsrunloop


【解决方案1】:

从早期的 Cocoa 开始,当恐龙在地球上漫游时,岩石很软,NeXT 工作站是新的,直到 10.6 出现,最常见的多任务处理类型是运行循环。这是协作式多任务处理。没有线程。没有抢占式调度程序或内核。没有上下文切换。只有一个大的运行循环说“现在需要做什么?”并运行它。当那件事完成时,它会等待下一件需要做的事情并运行它。它实际上是一个很大的while(true) 循环。好吧,从技术上讲,这行代码是:

for (;;) { ... }

您可以在CFRunLoop.c 中亲自查看。寻找__CFRunLoopRun

NSTimer 是在那个时候发明的。它所做的一切都是在运行循环中做一个注释,告诉它“当这个时间过去时,请执行此操作”。 (比这稍微复杂一点,因为它使用 mach 端口,请在同一文件中查找 __CFRunLoopTimerSchedule 以获取详细信息,但基本上就是这样。)

所以重点是,没有魔法。只有一个大的for(;;) 循环来处理这些东西。必须有一些东西来运行它。当您启动它时(使用run),它不会返回。这是一个无限循环。没有“背景”。没有其他线程。这就是为什么您需要按照 BNR 告诉您的顺序做事的原因。否则你的下一行代码不会运行。

当然,在 iOS 应用程序和 OS X GUI 应用程序中,您通常不必自己执行此操作。运行循环是在程序启动期间为您创建的,整个主线程都存在于其中。这是大多数时候打电话给你的事情。你不叫它。但是如果你在主线程之外的线程上,并且你想使用运行循环功能,你将不得不自己运行它。

今天,很多事情都是使用 GCD 而不是运行循环来完成的。这就是我提到的“直到 10.6 出来”。它真的改变了可可的世界。但是大量的 Cocoa 仍然依赖于运行循环,即使您从未想过它仍然是大多数应用程序的主力。

在今天的大多数情况下,如果您必须创建一个运行循环才能使用NSTimer,那么您不应该使用NSTimer。只需使用dispatch_after。事实上,即使你确实有一个运行循环,这也是我今天大部分时间通常推荐的。

(你绝对应该阅读 @quelish 在 cmets 中给出的链接。这是关于运行循环的权威词。)

【讨论】:

  • 不错的答案。 GCD 主队列不是从运行循环中调度出来的吗?所以运行循环仍然是 10.6 后的基础。
  • @CRD 这绝对是基本的。 “即使您从未想过它,它仍然是大多数应用程序的主力。”但在大多数情况下,GCD 是应用层更好的解决方案。并且对 Swift 更加友好。
  • 抱歉 Rob,我本来可以更清楚的。并不是说它肯定是“仍然是主力”,而是它将保持中心地位,因为整个 GUI/事件模型都是围绕它构建的,并且它运行 GCD 主队列。 GCD 不直接用于处理鼠标、键盘、窗口等事件。摆脱这一点将是一个很大的变化,所以我预计运行循环不会很快消失。
  • @Woodstock 这不是一个紧凑的空循环。当没有消息要处理时,它会阻塞。如果您查看代码,您会看到在 Darwin 上它调用 mach_msg 以让步给操作系统,等待消息。在 WIN32 上,它使用 MsgWaitForMultipleObjects。 for(;;) 的重点在于它是一个无限循环,而不是它把所有时间都花在 CPU 上。
  • @Rob 非常感谢您的回复。很高兴了解这些东西。完全有道理。有趣的是,我们在学术上学习从不睡觉,或者使用 goto 等。他们在大学里没有。然而睡眠是在低级内核代码中完成的:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-04
  • 1970-01-01
  • 2011-12-12
  • 2010-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多