当我的应用程序启动时,我有很多连接,所以我想把它们放在后台线程上,这样我就可以在它们全部完成之前建立新连接而不是起始连接。
下面,threadedRequest:
是一个启动NSURLConnection的方法,但是当我在performSelectorInBackground:withObject:
子句中调用if
时,连接开始,但永远不会结束。 else
子句工作正常,并从连接
if (background)
{
[self performSelectorInBackground: @selector(threadedRequest:) withObject: args];
}
else
{
[self performSelector: @selector(threadedRequest:) onThread: [NSThread mainThread] withObject: args waitUntilDone: NO];
}
答案 0 :(得分:1)
如果要在后台执行NSURLConnection
,则必须对适用于后台线程中的NSURLConnectionDataDelegate
方法的特殊条件敏感。您有几种选择:
使用其中一个非委托替代方案。如果您在后台执行此操作,则可以使用sendSynchronousRequest
,或者如果只是从简单网址请求数据,则可以使用NSData
类方法dataWithURL
。
如果您确实需要代理版本(因为您需要通过didReceiveData
进行更新,或者因为您需要其中一种NSURLConnectDelegate
方法进行身份验证等,您需要几个基本版本选项:
您可以创建NSOperationQueue
并为连接设置委托队列。例如,而不是:
- (void)startConnection:(NSURL *)url
{
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self];
}
你可以这样做:
- (void)startConnection:(NSURL *)url
{
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[connection setDelegateQueue:self.connectionDelegateQueue];
[connection start];
}
或者,您可以执行AFNetworking所做的事情(有关示例实现,请参阅AFURLConnectionOperation.m
):
为NSThread
电话创建专用的NSURLConnectionDataDelegate
;
在该线程上启动NSRunLoop
;
使用与上述startImmediately:NO
init方法相同的NSURLConnection
版本;以及
在scheduleInRunLoop
之前使用NSURLConnection
的{{1}}选项。
或者,最简单的方法是,您可以使用AFNetworking
两个观察结果:
我可能倾向于使用操作或调度队列而不是start
。请参阅Concurrency Programming Guide。
顺便说一句,您应该知道iOS可以同时执行多少并发performSelectorInBackground
请求的限制(我相信它是5或6)。因此,如果您发起十几个后台请求然后发起“前台”请求,则“前台”请求可能不立即启动。如果要避免此潜在问题,您可能希望限制可同时运行的后台请求数。
就个人而言,当我想限制网络请求的数量时,我将我的后台请求添加到NSURLConnection
并设置maximum concurrent operations的数量(例如,我通常使用4),享受并发操作,而不是尝试执行比iOS允许的更多同时连接。顺便说一下,当利用操作队列的NSOperationQueue
功能时,您必须确保请求是同步的(或将异步连接包装在自定义maxConcurrentOperations
中,直到连接为止才会终止完成或失败)。