调用(NSRunLoop)-run()和CFRunLoopRun()有什么区别



我正在学习iOS运行循环。网络上的一些文章向我展示了这样的代码:

- (void)memoryIssue {
for (int i = 0; i < 10000; i++) {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(runThread) object:nil];
[thread setName:thread_name];
[thread start];
[self performSelector:@selector(stopThread) onThread:thread withObject:nil waitUntilDone:YES];
}
}
- (void)runThread {
NSLog(@"current thread = %@", [NSThread currentThread]);
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
static NSMachPort *port;
if (!port) {
port = [NSMachPort port];
}
[runLoop addPort:port forMode:NSDefaultRunLoopMode];
//    CFRunLoopRun();  //All right
[runLoop run];  // ⚠️Thread not exit...!
}
- (void)stopThread {
CFRunLoopStop(CFRunLoopGetCurrent());
NSThread *thread = [NSThread currentThread];
[thread cancel];
}

使用CFRunLoopRun()时,它就很好。在每个 for 循环中,创建一个线程,然后退出。然而,至于[runLoop run],内存不断增长,最后应用程序由于"-[NSThread start]:线程创建失败,错误 35"(达到线程计数上限?

**我的问题:

  1. -run()CFRunLoopRun()有什么区别?我以为前者只是后者的包装。

  2. 该代码似乎打算显示退出线程的正确方法。在现实生活中的发展中是否实用?

CFRunLoopRun文档告诉我们:

当前线程的运行循环在默认模式下运行(请参阅默认运行循环模式),直到运行循环停止并CFRunLoopStop或从默认运行循环模式中删除所有源和计时器。

但是run文档没有对此进行任何引用。它说:

如果没有输入源或计时器连接到运行循环,则此方法立即退出;否则,它通过重复调用runMode:beforeDate:NSDefaultRunLoopMode中运行接收器。换句话说,此方法有效地开始了一个无限循环,该循环处理来自运行循环的输入源和计时器的数据。

但它继续警告:

从运行循环

中手动删除所有已知的输入源和计时器并不能保证运行循环将退出。 macOS 可以根据需要安装和删除其他输入源,以处理针对接收方线程的请求。因此,这些源可能会阻止运行循环退出。

如果希望运行循环终止,则不应使用此方法。相反,请使用其他运行方法之一,并在循环中检查您自己的其他任意条件。一个简单的例子是:

BOOL shouldKeepRunning = YES; // global
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);

其中shouldKeepRunning设置为NO程序中的其他位置。

我还建议您参考线程编程指南:终止线程。

你问:

该代码似乎打算显示退出线程的正确方法。在现实生活中的发展中是否实用?

不,编写我们自己的NSThread代码是非常罕见的。Grand Central Dispatch(GCD)消除了所有这些麻烦。它更高效(因为它有准备好的工作线程池,不需要旋转循环或每个线程的NSRunLoop等),并且编写代码要容易得多。我不建议编写NSThread代码,除非有一些非常具体的问题,你不能用GCD轻松解决。


顺便说一下,请注意,当您编写NSThread代码时,您应该让您的线程设置自己的自动发布池(尽管我们会使用@autoreleasepool { ... }而不是该指南中概述的模式)。例如:

- (void)runThread {
@autoreleasepool {
...
}
}

如果您使用 GCD,则会为您处理此内存管理。


如果需要有关NSThreadNSRunLoop等的更多信息,请参阅线程编程指南。或者为自己省去很多痛苦,只使用GCD。

相关内容

  • 没有找到相关文章

最新更新