NSURLConnection didReceiveData not called

I read a lot of posts repeating the same thing: when you use NSURLConnection, delegate methods are not called. I understand that the Apple document is incomplete and refers to outdated methods, which is a shame, but I cannot find a solution.

Code for the request:

// 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 }); 

... and code for delegate methods:

 - (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]; } 

There are not many mistakes here, but I have seen a few things:

  • No matter what happens, didReceiveData is never called, so I get no data
  • ... but the data is being transmitted (I checked with tcpdump )
  • ... and other methods are called successfully.
  • If I use NSURLConnectionDownloadDelegate instead of NSURLConnectionDataDelegate , everything works, but I can not hold the downloaded file (this is a known error).
  • The request is not freed until terminated by improper memory management
  • Nothing will change if I use a standard HTML page somewhere on the web, as my URL
  • The request is sent from the main queue

I do not want to use a third-party library, since, ultimately, these requests should be included in my own library, and I would like to minimize dependencies. If I need to, I will use CFNetwork directly, but it will be a huge pain in you-know-what.

If you have any ideas, this will help a lot. Thanks!

+6
source share
4 answers

I like to use the sendAsynchronousRequest method .. there is less information during the connection, but the code is much cleaner.

  [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); }]; 

From Apple:

By default, a connection is scheduled for the current thread in the default when it is created. If you create a connection with the initWithRequest: delegate: startImmediately: method and provide NO for the startImmediately parameter, you can schedule the connection to another startup loop or mode before starting using the start method. You can schedule a connection in several cycles and startup modes, or on the same startup cycle in several modes.

If there is no reason to explicitly run it in [NSRunLoop currentRunLoop], you can remove these two lines:

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

or change the mode to NSDefaultRunLoopMode

+2
source

I ran into the same problem. Very annoying, but it seems that if you implement this method:

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

Then connection:didReceiveData: will never be called. You should use connectionDidFinishLoading: instead ... Yes, the docs say it is deprecated, but I think it is only because this method has moved from NSURLConnectionDelegate to NSURLConnectionDataDelegate .

+13
source

The NSURLConnection API says that the "..delegate" methods are called in the thread that started the asynchronous load operation for the associated NSURLConnection object. "

Since dispatch_async will start a new thread and NSURLConnection will not jump to another threat caused by the callback, therefore do not use dispatch_async with NSURLConnection.

You do not need to be afraid of a frozen user interface, NSURLConnection provides only asynchronous load controls.

If you have more files to download , you can start some connection in the first place, and later they finished, in the connectionDidFinishLoading method: you can start new connections.

 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; } } 
+1
source

One possible reason is that the outgoing NSURLRequest been configured to -HTTPMethod HEAD . Pretty hard to do it by accident!

0
source

Source: https://habr.com/ru/post/920152/


All Articles