Daniel
Daniel

Reputation: 23359

GCD network requests failing on iOS 4

I have the following code in my application to load some data from my API. It works fine, great in fact in iOS 5 but on iOS 4 I am getting so many responses with status 204.

This only happens on iOS 4, this could have been treated as an API error, but it works great in the browser, on Rested.app, on iOS 5 etc... only iOS 4 fails, it fails in the simulator and on the device (iPhone 4).

I am calling this code each time I load a cell into a table view. I have a core data object with a load state, set to no initially, if it's not loaded I perform this code, if it's loaded, I skip this code. In the mean time I display a spinner inside the cell on the table view.

I am sure it's a problem with multiple requests in GCD on iOS 4.

Can anyone spot anything wrong with my code snippet?

-(void)myFunction{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // query users participations (Network)

        NSError * _urlError = nil;
        NSString * url = [NSString stringWithFormat:@"my api url"];
        NSMutableURLRequest * loginHTTPRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        [loginHTTPRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"];

        NSLog(@"Description: %@", [loginHTTPRequest description]);

        NSHTTPURLResponse   * _responseHeaders  = nil;
        NSData              * responseData      = [NSURLConnection sendSynchronousRequest:loginHTTPRequest 
                                                                        returningResponse:&_responseHeaders 
                                                                                    error:&_urlError];
        if(_urlError != nil){
            dispatch_async( dispatch_get_main_queue(), ^{
                // alert network connection error
            });
            return;
        }

        NSString *json_string = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

        SBJsonParser *parser = [[SBJsonParser alloc] init];
        NSDictionary * jsonData = [NSDictionary dictionaryWithDictionary:[parser objectWithString:json_string]];
        [json_string release];
        [parser release];

        dispatch_async( dispatch_get_main_queue(), ^{
            // here [_responseHeaders statusCode] keeps returning 204 and there is nothing in responseData

            // do some Core Data stuff
        });

    });
}

UPDATE

Note this code is working fine if called even with a for loop repeatedly, the issue is when I invoke this method from tableView:cellForRowAtIndexPath:

I have Core Data objects with a property "isLoaded" set to NO and changed to YES upon remote load. When my tableview's datasource loads the cells for each object, the tableView:cellForRowAtIndexPath: method calls this function if the object's "isLoaded" property is NO.

I suspected the problem may be because there 2 or more simultaneous calls to the API happening when the table is loaded and reloaded. Each successful load from the api invokes reloadData for that tableview.

This lets me have a pre filled tableview with spinners and asynchronously load in my data as I need it on screen which is nice because I can efficiently use NSFetchedResultsController with lazy loading my objects core data.

(I have an endpoint for all my objects returning an array of object id's - I create Core Data objects with only the ID's, all rest of data, name, date etc etc... is not loaded until it's needed).

When I start scrolling around the new cells which are created/reused call this method and they always get a 200 response with the data. it's only the first loading which causes this "block".

Upvotes: 2

Views: 332

Answers (2)

Daniel
Daniel

Reputation: 23359

I think I found the problem, I was performing synchronous requests on an asynchronous GCD thread, and for some reason timeouts were occurring, but only on requests in iOS 4, maybe the headers are sent slightly differently from iOS 4 which is causing the API to take longer to respond ? Or maybe multiple (as in simultaneous to the millisecond) requests sent from different threads synchronously on an asynchronous thread were clashing in the system before being sent ?

Anyhow... this didn't seem to be the case calling google.com or even my own private server, so it must be something to do with the headers and multiple requests...

I am using asi http from github and it's working a lot more efficiently, now I am not using GCD for these requests, just an ASI queue.

Any final thoughts on iOS 4 synchronous requests performing on an asynchronous GCD thread with possible timeouts not being respected and returning early with a status 204 ?

Upvotes: 1

Scott Corscadden
Scott Corscadden

Reputation: 2860

Ok - if it is https, then you probably can't get away with using sendSynchronousRequest. The documentation states that things like [NSURLConnection connection:didReceiveAuthenticationChallenge:] won't call some key things, i.e.:

If authentication is required in order to download the request, the required credentials must be specified as part of the URL. If authentication fails, or credentials are missing, the connection will attempt to continue without credentials.

I'm still surprised it's working on iOS5, to be honest. I think you'll have to use asynchronous methods to at least debug it to find out what is going on.

Upvotes: 0

Related Questions