GCD块中的RunLoop如何在没有源的情况下工作

4
我正在尝试了解iOS中的多线程编程。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
               , ^{
                    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL   URLWithString:@"http://www.google.com"]];
                    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

                    if (connection == nil) {
                        NSLog(@"Request failed");

                    } else {
                        NSLog(@"Request sent");
                    }
                    [[NSRunLoop currentRunLoop] run];//How does this work?
                   });

这段代码可正常工作且回调符合预期。
在文档中https://developer.apple.com/library/ios/documentation/cocoa/Reference/Foundation/Classes/NSRunLoop_Class/Reference/Reference.html#//apple_ref/occ/instm/NSRunLoop/run中提到,'run'方法'将接收者置于永久循环中,在此期间它会处理所有附加的输入源的数据。'
现在,在上述代码中,我没有将任何源附加到runLoop上。它是如何工作的?

为什么需要执行[[NSRunLoop currentRunLoop] run]? - skyylex
3
为了获得NSURLConnectionDelegate回调。没有它,回调将不会被调用。 - optimus
1个回答

5
每个 NSThread 都需要连接到 runloop 才能正常工作。当您调用 dispatch_async() 时,GCD 会创建一个带有 runloop 的线程,您将使用它与 [NSRunLoop curentRunLoop] 一起使用。当您使用 NSURLConnection 创建一些工作时,据我所知,创建的连接将作为源附加到当前 runloop。因此,如果您希望 runloop 保持活动状态而不进入睡眠状态,请执行 [[NSRunLoop curentRunLoop] run]。在这种情况下,当连接接收到消息时,runloop 将获取该消息。
希望这可以帮助您。
更新:
根据 Apple 的文档: performSelector 可以是输入源
Cocoa 定义了一个自定义输入源,允许您在任何线程上执行选择器。
这就是为什么您需要执行保持 runloop 活动的操作:
在另一个线程上执行选择器时,目标线程必须具有活动运行循环。

谢谢。在进一步寻找答案时,我发现每个线程都是由一个运行循环创建的,并且根据文档,在NSURLConnection中,它会将连接安排在当前runLoop上。 - optimus
1
@optimus 我不明白。我认为这并没有回答你的问题。无论如何,输入源是什么? - ljk321
根据 NSURLConnection.h 中的文档,“使用 +connectionWithRequest:delegate: 或 -initWithRequest:delegate: 方法创建的 NSURLConnection 会立即在当前 runloop 上安排,并且不需要发送 -start 消息来开始资源加载。<p>”这意味着 NSURLConnection 正在将输入源附加到 runloop 上。它是如何实现的(performSelector、自定义输入源或其他方式)是一些实现细节,我并不期望在答案中看到。 - optimus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接