NSTimer
,NSTask
,NSThread
和NSRunloop
之间有什么区别,是否有关于何时使用这些内容的指南?
答案 0 :(得分:43)
每个程序至少运行一个线程。您可以将每个线程视为一个独立的程序执行过程,每个过程都与其他线程并行运行。
如果您有某种用户界面或需要侦听事件的其他代码(如网络端口),则需要运行循环。每个NSThread都会自动获得自己的运行循环,而您很少需要直接关注它们。运行循环还负责创建和释放自动释放池。
[编辑:有关自动释放池的更多讨论,请参阅注释。要记住的最重要的一点是新线程必须注意设置自动释放池。例如,使用detachNewThreadSelector调用的方法(见下文)应该包含以下第一行和最后一行:
NSAutoreleasePool *pool = [ [ NSAutoreleasePool alloc ] init ];
[code here]
[pool release];
这同样适用于使用其他技术产生的线程。]
在所有UI处理正在进行的主线程中,运行循环非常重要,因为它使接口保持活动状态。这就是为什么你永远不应该在主线程上运行耗时的代码:它会在线程上耗尽所有时间并且不允许运行循环经常运行,从而导致锁定或慢速接口。如果您需要执行耗时的计算,或者让任务在后台运行,您应该创建一个新线程。同样,您可能不必考虑正在创建的新运行循环。在新线程中执行方法的简便方法:
[NSThread detachNewThreadSelector:@selector(theSelector) toTarget:self withObject:nil];
线程间通信可能很棘手,您应该了解方法performSelector:onThread:withObject:waitUntilDone:
和performSelectorOnMainThread:withObject:waitUntilDone:
(跨线程here发送NSNotification的重要提示。)
计时器也由运行循环处理。与运行循环相比,您可能经常在程序中直接使用计时器。创建计时器的最简单方法是:
[self performSelector:@selector(aSelector) withObject:nil afterDelay:1.0];
但有时你想自己创建和管理NSTimer对象,例如能够取消和重复使用计时器。
NSTask 用于运行另一个程序作为当前程序的子进程。它有点类似于启动一个单独的线程,但如果一个子进程崩溃,你的主程序将继续运行。程序之间的通信也与同一进程中多个线程之间的通信非常不同。
您使用“iphone”标记了您的问题,而在iPhone上您永远不会使用NSTasks。
当您需要处理大量不同的任务,将它们放入队列和/或在单独的线程中处理它们时,会使用NSOperations (尽管它们没有 >在不同的线程中运行)。如果您的应用程序需要只创建一些专用线程,那么就没有理由使用NSOperation类。但是,如果您经常生成必须跟踪的任务(如与服务器通信),NSOperation和NSOperationQueue将会派上用场。
答案 1 :(得分:4)
NSTimer
是一个计时器对象,是将来在对象上调用选择器的一种方法。NSThread
是一个线程类。我想你知道什么是线程。NSTask
是一个进程类,一种从程序中运行另一个程序的方法。NSOperation
(我正在添加问题)对于单个任务来说是一个非常好的抽象。您将操作嵌入此类中,并且可以通过NSOperationQueue
类轻松地同时执行。NSRunLoop
是最难理解的。在某种程度上抽象并调整select()
unix系统调用,管理输入源以及在线程上调度事件和计时器。答案 2 :(得分:3)
其他答案在总结计时器,任务和线程方面做得非常好。我想对NSRunloop进行更多评论,因为我认为其他大多数答案仍然存在一些混乱。来自NSRunloop文档:
NSRunLoop对象处理输入 用于鼠标和键盘等来源 来自窗口系统的事件,NSPort 对象和NSConnection对象。一个 NSRunLoop对象也处理 NSTimer活动。
也
一般情况下,您的应用程序没有 需要创建或显式 管理NSRunLoop对象。每 NSThread对象,包括 应用程序的主线程,有一个 NSRunLoop对象自动创建 根据需要。如果你需要 访问当前线程的运行循环, 你用类方法这样做 currentRunLoop。
将NSRunloop视为特定线程的主要事件处理和调度循环。它从输入设备读取服务,为任何需要服务的对象提供服务,并适当地调度数据。