Question

I have a UITableView, when a cell is selected, I make a service call to asynchronously download a PDF file from a web service. It works great, until you select multiple cells directly after one-another (individually), then things start going south..

Here's some (stripped down) code to clarify:

Inside MasterViewController.m:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //To uniquely identify this field, I build a simple string using the indexPath.
    NSString *key = [[NSString alloc]initWithFormat:@"%d.%d",pIndex.section,pIndex.row];

    //Use a pre-populated NSDictionary to specify the file I want from the server.
    NSString *reportID = [reportDictionary valueForKey:key];

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/RequestReportWithID",myConnectionObject.ServiceURL]];

    NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithObjectsAndKeys:reportID, @"reportID", nil];

    NSData *requestData = [NSJSONSerialization dataWithJSONObject:dic options:0 error:nil];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody: requestData];

    //Create a new object as delegate to receive the data, also add the key to assist with identification.
    ReportDownloader *newReportDownloader = [[ReportDownloader alloc]initWithDelegate:self andKey:key];

    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:newReportDownloader];
    if (connection)
    {
        //Nothing to do here, request was made.
    }
}

Inside ReportDownloader.m:

long long expectedReportSize;
NSString *key;
NSData *thisReport;

-(NSObject*)initWithDelegate:(NSObject*)pDelegate andKey:(NSString*)pKey
{
    myTypedDelegate = (MasterViewController*)pDelegate;
    Key = pKey;
    return self;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    expectedReportSize = [response expectedContentLength];
    NSLog(@"Key:%@, Expected Size=%lld bytes",Key, [response expectedContentLength]);
    thisReport = [[NSMutableData alloc] init];
}

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

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{
    //Here is where things go wrong...
    NSLog(@"Key:%@, Actual Size=%ld bytes",Key, (unsigned long)[thisReport length]);
}

The above code works fine for a single report. And on a fast line, it works fine for 3-4 reports, but try to do more than that and the Expected length starts mismatching the Actual length. And I can't understand whyyyyy....

See the output generated by the code above: (Notice that only the report for indexPath 1.1 was downloaded correctly)

Key:1.0, Expected Size=304006 bytes
Key:1.3, Expected Size=124922 bytes
Key:1.0,   Actual Size=369494 bytes
Key:1.3,   Actual Size=380030 bytes
Key:1.2, Expected Size=179840 bytes
Key:1.4, Expected Size=377046 bytes
Key:1.2,   Actual Size=114376 bytes
Key:1.5, Expected Size=175633 bytes
Key:1.4,   Actual Size=180558 bytes
Key:1.5,   Actual Size=274549 bytes
Key:1.1, Expected Size=443135 bytes
Key:1.1,   Actual Size=443135 bytes

The data corruption is confirmed when trying to open the PDF documents, which fail for all file's who's data size didn't match the expectedContentLength.

I am completely baffled by this behaviour, I'm hoping that I'm making an obvious n00b mistake and that someone here spots it.

The main reason WHY I made the ReportDownloader class was to avoid problems like this one.

Thanks in advance to whoever takes the time to scan my code!

Was it helpful?

Solution

Ok, the solution to this problem can be found here: https://stackoverflow.com/a/1938395/1014983 This answer by James Wald, although not the question's accepted answer, completely solved all my problems with multiple simultaneous async NSURLConnections.

Let me know if you need some help with the implementation, but it's pretty straight forward.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top