(异步) NSURLConnection:底层发生了什么?

3

我知道启动线程进行网络请求会使代码变得更加丑陋,所以可能需要调用performSelectorOnMainThread:方法来调用代理方法。

在iOS编程中,我知道如何使用它并且它非常好用。但是,我想知道如何在没有UIApplication处理事件等情况下,在命令行实用程序中让它工作。

我已经尝试过,似乎异步调用返回时程序立即退出,而委托方法无法被调用。我希望深入了解它是如何工作的。

2个回答

7
根据文档,连接的代理方法会在启动连接的同一线程上被调用。因此,为了保持该线程运行直到连接完成其操作,请:
int main(int argc, char *argv[])
{   
    // ...
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:del startImmediately:YES];
    CFRunLoopRun();    // Run this run loop, run!
    // ...
}

接着,当连接表示已完成时,委托可以停止运行循环:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // This returns control to wherever you called
    // CFRunLoopRun() from, so you can still clean up
    // or do other interesting things.
    CFRunLoopStop(CFRunLoopGetCurrent());
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"Error: %@", error);
    CFRunLoopStop(CFRunLoopGetCurrent());
}

我意识到这只是纯粹的实用,无法满足您对更深层次理解的渴望;我认为我对此的理解并不比您更深。 - jscs
这向我展示了如何做我想做的事情。我想要更深入地理解(a)完成它和(b)满足好奇心。所以这仍然是有点帮助的。谢谢! - Derrick

2
代理方法调用是在启动连接的线程的运行循环中安排的。因此,它不一定是主线程。您可以从任何线程执行此操作。但是,必须有一个运行时间足够长以处理这些委托消息的运行循环。
默认情况下,运行循环必须在其默认模式下运行,才能触发这些委托方法。例如,默认情况下,如果您从主线程开始异步连接,则在用户滚动表格视图等操作时,您的委托方法将不会触发。
但是,您可以通过使用-[NSURLConnection scheduleInRunLoop:forMode:]在任何其他运行循环和/或任何运行循环模式上安排代理回调来更改此设置。
我希望这就是您要问的内容。

1
@Derrick,只是为了明确起见,这是因为在滚动时,主线程的运行循环不处于其默认模式。 - Firoze Lafeer
这接近我想表达的意思。希望我没有超出问题范围太远。如果我不仅使用Foundation框架(没有UIKit,AppKit等),那么我是否需要创建RunLoop才能使NSURLConnection(以及类似的东西)像在iOS上一样正确地运行? - Derrick
你不需要创建一个运行循环。但是你需要配置和运行它。 - Firoze Lafeer
@Derrick:如果你在命令行工具中使用NSURLConnection,你应该只需使用+sendSynchronousRequest:returningResponse:error:,因为与此同时没有其他需要做的事情(例如,允许用户点击按钮)。 - jscs
@Josh 是的,我知道在实际的命令行工具中异步执行并不切实际。但原因是我正在编写一个使用异步版本的库。我目前正在使用一个简单的iOS应用程序来测试它。能够在没有GUI或任何其他东西的情况下进行开发将是很好的。 - Derrick

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