NSURLConnection doesn't receive data when crea

2019-09-05 07:32发布

问题:

I have been searching for this problem on the SOF for several days and I still have not found the solution (say the same problem) yet.

I'm making and app that downloads 5 images simultaneously in an URL list (each image is on a different server).

I have an ImageDownloader class subclasses NSOperation and implements the NSURLConnectionDataDelegate.

So that I can add an instance of ImageDownloader to an operationQueue in the ViewController and it will run in a separate thread under the operationQueue. The line that add the downloader to the operationQueue is here:

downloader = [[ImageDownloader alloc] init];
[downloader downloadImageWithURL:[controller.URList objectForKey:[NSString stringWithFormat:@"%d",downloadIndex]] queue:queue andTag:downloadIndex + 100]; //my custom initialize
downloader.delegate = self;
[queue addOperation:downloader]; //use the addOperation method

Everything works fine in iOS6 but messed up in iOS5 (5.0 on my test device and 5.1 on my SDK), it just doesn't receive any response nor data by performing the methods didReceiveResponse and didReceiveData at all (these 2 methods are not jumped in).

After the timeout was exceeded, the runloop jumps into didFailWithError method and the program stalls.

As I understand, this means the runloop still runs right?

I tried to print out the error and all I got is: The request timed out.

When I reduce the number of downloading instances to 2 then it runs, but not with >=3 downloading instances.

One more information is that my network connection does limit the number of connection. But it work fine in iOS6, why it just doesn't work on iOS5?

I can still load the web in the simulator while the app is downloading.

So what kind of problem is this and how can I get over this problem?

Thanks in advance.

*Update:* as there are many classes and the problem's not been clearly detected yet, I will share here the whole project. You can download it directly from here: DownloadingImage

回答1:

As I just found out, if you're using credentials there is a chance that the server will reject them randomly every once in a while. So if you have a check to make sure previousFailureCount == 0 then you will most likely have a bug.



回答2:

I've just figured out where my problem is, but not really understand why.

In my ImageDownloader class, I set up a runloop with done and currentRunLoop variables. In the main method, I have a while loop for forcing the currentRunLoop run.

As I remove those "runLoop" stuffs, the app runs smoothly on both iOS6 and iOS5.

So change the entire ImageDownloader.m with these lines then it works (I commented out some useless (say harmful) lines):

//
//  ImageLoader.m
//  DownloadImagesTableView
//
//  Created by Viet Ta Quoc on 6/25/13.
//  Copyright (c) 2013 Viet Ta Quoc. All rights reserved.
//

#import "ImageDownloader.h"

@implementation ImageDownloader
@synthesize downloadData,delegate,queue,done,customTag;
NSRunLoop *currentRunLoop;

-(void)downloadImageWithURL:(NSString *)imageUrl queue:(NSOperationQueue*)opQueue andTag:(int)tag{
    self.customTag= tag;
    self.queue = opQueue;
//    self.done = NO;
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:imageUrl] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    [connection start];
//    currentRunLoop = [NSRunLoop currentRunLoop];
    NSLog(@"Start downloading image %d...",customTag);
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"Received response...");
    downloadData=[[NSMutableData alloc] initWithLength:0];
    expectedDataLength=[response expectedContentLength];
    NSLog(@"Image %d size: %lld kb",customTag,[response expectedContentLength]/1024);
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    float receivedLenght = [data length];
    receivedDataLength=(receivedDataLength+receivedLenght);
    float progress=(float)receivedDataLength/(float)expectedDataLength;
    [delegate updateProgess:progress andIndex:[NSIndexPath indexPathForRow:customTag-100 inSection:0]];
    [self.downloadData appendData:data];
//    NSLog(@"Percentage of data received of tag %d: %f %%",self.customTag,progress*100);
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
    [delegate finishedDownloadingImage:downloadData andTag:customTag];
//    done = YES;
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Warning" message:@"Network Connection Failed?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
//    NSLog(@"%@",[error debugDescription]);
    NSLog(@"Connection failed! Error - %@ %@",[error localizedDescription],[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
    [alert show];
}

-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
    NSLog(@"Got here *(*&(**&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&(*&");
}

-(void)main{
//    do{
////        NSLog(@"Running....1");
//        [currentRunLoop runUntilDate:[NSDate distantFuture]];
//        //        [currentRunLoop run];
//    } while (!done);
//    [currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]];
}
@end

Thank you guys for your supports.

==================================================================================

P/s: for anyone who interested in this problem, I update here my entire solution: DownloadImage_Final