NSURLConnection didReceiveData未被调用

时间:2012-07-10 19:27:07

标签: objective-c ios nsurlconnection

我已经阅读了大量的消息,再次说同样的事情:当你使用NSURLConnection时,委托方法不被称为。我理解Apple的文档是不完整的,并且引用了弃用的方法,这是一种耻辱,但我似乎无法找到解决方案。

请求代码在那里:

// Create request
NSURL *urlObj = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlObj cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];

if (![NSURLConnection canHandleRequest:request]) {
    NSLog(@"Can't handle request...");
    return;
}

// Start connection
dispatch_async(dispatch_get_main_queue(), ^{
    self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; // Edited
});

...委托方法的代码在这里:

- (void) connection:(NSURLConnection *)_connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"Receiving response: %@, status %d", [(NSHTTPURLResponse*)response allHeaderFields], [(NSHTTPURLResponse*) response statusCode]);
    self.data = [NSMutableData data];
}

- (void) connection:(NSURLConnection *)_connection didFailWithError:(NSError *)error {
    NSLog(@"Connection failed: %@", error);
    [self _finish];
}

- (void) connection:(NSURLConnection *)_connection didReceiveData:(NSData *)_data {
    [data appendData:_data];
}

- (void)connectionDidFinishDownloading:(NSURLConnection *)_connection destinationURL:(NSURL *) destinationURL {
    NSLog(@"Connection done!");
    [self _finish];
}

这里没有很多错误检查,但我确定了一些事情:

  • 无论发生什么,didReceiveData 从不被调用,所以我没有得到任何数据
  • ...但数据已转移(我使用tcpdump
  • 进行了检查
  • ...并成功调用其他方法。
  • 如果我使用NSURLConnectionDownloadDelegate代替NSURLConnectionDataDelegate,一切正常,但我无法保留下载的文件(这是一个已知错误)
  • 在内存管理不善之前,请求未被解除分配
  • 如果我在互联网上某处使用标准HTML页面作为我的网址
  • ,则不会有任何变化
  • 请求从主队列启动

我不想使用第三方库,因为最终,这些请求将包含在我自己的库中,并且我希望最小化依赖项。如果必须的话,我会直接使用CFNetwork,但在你知道什么的情况下,这将是一个巨大的痛苦。

如果您有任何想法,那将会有很大帮助。谢谢!

4 个答案:

答案 0 :(得分:13)

我遇到了同样的问题。非常讨厌,但似乎如果你实现这个方法:

- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL

然后永远不会调用connection:didReceiveData:。您必须使用connectionDidFinishLoading:代替...是的,文档说它已被弃用,但我认为这仅仅是因为此方法已从NSURLConnectionDelegate移至NSURLConnectionDataDelegate

答案 1 :(得分:2)

我喜欢使用sendAsynchronousRequest方法..连接过程中信息较少,但代码更清晰。

    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
        if (data){
            //do something with data
        }
        else if (error)
            NSLog(@"%@",error);
    }];

来自Apple:

  

默认情况下,会在当前线程上安排连接   创建时的默认模式。如果您创建了一个连接   initWithRequest:delegate:startImmediately:方法并为其提供NO   startImmediately参数,您可以在a上安排连接   使用start方法启动之前的不同运行循环或模式。   您可以在多个运行循环和模式上安排连接,也可以安装   多种模式下的相同运行循环。

除非有理由在[NSRunLoop currentRunLoop]中明确运行它, 你可以删除这两行:

[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];

或将模式更改为NSDefaultRunLoopMode

答案 2 :(得分:1)

NSURLConnection API说“..线程上的..delegate方法被称为,它启动了相关NSURLConnection对象的异步加载操作。”

因为dispatch_async将启动新线程,并且NSURLConnection不会传递回另一个威胁,所以不要将dispatch_async 与NSURLConnection一起使用。

您不必担心冻结的用户界面,NSURLConnection只提供异步加载的控件。

如果你有要下载的文件,你可以在第一回合开始一些连接,之后他们就完成了,在connectionDidFinishLoading:方法中你可以开始新的连接。

int i=0;
for (RetrieveOneDocument *doc in self.documents) {

    if (i<5) {
         [[NSURLConnection alloc] initWithRequest:request delegate:self];
        i++;
    }
}

..

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    ii++;
    if(ii == 5) {
         [[NSURLConnection alloc] initWithRequest:request delegate:self];
        ii=0;
    }
}

答案 3 :(得分:0)

一个可能的原因是,传出的NSURLRequest已设置为-HTTPMethod HEAD。虽然很难做到这一点!