6

我已经阅读了大量的消息,一遍遍地重复着同样的事情:当你使用 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,一切正常,但我无法保留下载的文件(这是一个已知的错误)
  • 错误的内存管理在完成之前不会释放请求
  • 如果我在 Internet 上的某个地方使用标准 HTML 页面作为我的 URL,什么都不会改变
  • 请求从主队列中启动

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

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

4

4 回答 4

13

我遇到了同样的问题。很烦人,但似乎如果你实现这个方法:

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

然后connection:didReceiveData:永远不会被调用。你必须改用......是的,文档说它已被connectionDidFinishLoading:弃用,但我认为那只是因为这种方法从.NSURLConnectionDelegateNSURLConnectionDataDelegate

于 2013-03-15T18:56:28.057 回答
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);
    }];

来自苹果:

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

除非有理由在 [NSRunLoop currentRunLoop] 中显式运行它,否则您可以删除这两行:

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

或将模式更改为 NSDefaultRunLoopMode

于 2012-07-10T19:53:13.977 回答
1

NSURLConnection API 说“在为关联的 NSURLConnection 对象启动异步加载操作的线程上调用 ..delegate 方法。”

因为 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;
    }
}
于 2013-04-27T06:40:25.353 回答
0

一个可能的原因是传出NSURLRequest已设置为-HTTPMethod具有HEAD. 不过,很难做到这一点!

于 2012-11-05T15:31:52.737 回答