0

Hey I have an application I am working on and frequently I will get the following message:

 NSURLConnection error: Error Domain=NSURLErrorDomain Code=-1005 
"The network connection was lost."

My log will log this and than my application will freeze. My hope is, what is my best option to just send a notification that internet was lost and please try again rather than it closing my application?

Here is what I am doing:

User logins -> Main controller loads and runs this:

// EXECUTE SERVER CALL
-(void)makeRequests
{
    /* GRAB USERNAME TO BE SENT OVER FOR POPULATING DATA  */
    NSArray *get = [[SSKeychain allAccounts] init];
    NSString *username = [get[0] objectForKey:@"acct"];
    NSDictionary *dictionary = @{@"function": @"populateHomePage", @"username" : username};
        NSError *error = nil;
        NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&error];
        NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        if (error)
        NSLog(@"%s: JSON encode error: %@", __FUNCTION__, error);

        NSURL *url = [NSURL URLWithString:@"/IOS-Frame/grab-data.php"];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

        [request setHTTPMethod:@"POST"];
        NSString *params = [NSString stringWithFormat:@"json=%@",
                        [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        NSData *paramsData = [params dataUsingEncoding:NSUTF8StringEncoding];
        [request addValue:@"8bit" forHTTPHeaderField:@"Content-Transfer-Encoding"];
        [request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        [request addValue:[NSString stringWithFormat:@"%lu", (unsigned long)[paramsData length]] forHTTPHeaderField:@"Content-Length"];
        [request setHTTPBody:paramsData];


        // issue the request
        NSURLResponse *response = nil;
        NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        if (error)
            NSLog(@"%s: NSURLConnection error: %@", __FUNCTION__, error);

        NSString *responseString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
        NSLog(@"responseString: %@",responseString);
        // GRAB STATUS OBJECT
        NSDictionary* json = [NSJSONSerialization
                          JSONObjectWithData:returnData //1

                          options:kNilOptions
                          error:&error];
        self.dataGrabed_dictionary = [json objectForKey:@"retrieved_data"];
}
David Biga
  • 2,557
  • 6
  • 33
  • 57
  • 1
    Are you hitting your web services on the main thread? That's the only reason I can think that it would freeze your app. In general, you want to make web service calls on background threads to keep them from blocking your UI while in progress. – Stonz2 Jan 13 '15 at 18:45
  • Hey @stonz2 more specifically I am running a web api retrieve from my server to get data on load of a main view file. So what happens is, user logs in and gets sent to a table view which populates data from database on my webserver. – David Biga Jan 13 '15 at 18:47
  • Does your "web api retrieve" use the web service delegate callbacks such as `connectionDidFinishLoading:` and `connection:didFailWithError:` and, if so, are you handling it appropriately when the connection fails? It's hard to guess at what might be going wrong when you've supplied such little information on how your app works. – Stonz2 Jan 13 '15 at 18:51
  • @stonz2 check my update on what is running. – David Biga Jan 13 '15 at 18:53
  • I would wrap everything after the `if(error)` condition in an `else` statement (no sense in setting your response/json if the service failed) but I see nothing in your code there that would freeze your app. Does your main controller wait until data comes back from this method? If so, it could freeze up while it waits for something that never comes. – Stonz2 Jan 13 '15 at 19:00
  • http://stackoverflow.com/questions/1083701/how-to-check-for-an-active-internet-connection-on-iphone-sdk this helps you. Run your main thread in background and show up some activity controller until it loads. – Avis Jan 13 '15 at 19:00
  • @stonz2 okay I see, that fixed it :) – David Biga Jan 13 '15 at 19:07
  • @avis if you look at my method above, ifI just encode it with an else statement, wouldn't that be the best way to handle if there is no connection? – David Biga Jan 13 '15 at 19:08
  • it's not best way as of my knowledge. i got the same scenario and i approached in below answer way.@DavidBiga – Avis Jan 13 '15 at 19:13

2 Answers2

2

Follow this answer for internet connection test and just order methods in queue.

- (void)testInternetConnection
{
    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Yayyy, we have the interwebs!");

            //show activity indicator........block ui until data loads.

            //queue methods

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                // Save in the background

                [self makerequests];

                dispatch_async(dispatch_get_main_queue(), ^{
                    // Perform UI functions on the main thread!
                    //dismiss activity indicator
                });
            });

        });
    };

    // Internet is not reachable
    internetReachableFoo.unreachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Someone broke the internet :(");
            //show some alert....

        });
    };

    [internetReachableFoo startNotifier];
}

P.S. This is hint, not an exact answer.

Community
  • 1
  • 1
Avis
  • 495
  • 4
  • 13
  • Even if there is an internet connection at the beginning of the call, that's no guarantee that the connection won't be lost. – Stonz2 Jan 13 '15 at 19:13
  • yes! when it loses connection , it notifies but doesn't block ui right? @Stonz2 – Avis Jan 13 '15 at 19:14
  • From what I can tell, this is a one-off check to make sure there is an Internet connection and, if so, go ahead and perform whatever Internet-connection-required thing you want to do. However, if you _do_ have a connection, initiate a web service, and while that is still running your connection is interrupted, I don't see where this code could capture that. – Stonz2 Jan 13 '15 at 21:49
  • http://stackoverflow.com/questions/15749902/ios-dispatch-get-main-queue-is-called-multiple-times @Stonz2 – Avis Jan 13 '15 at 21:58
  • Apparently there is more going on there than I realized! Must be over my head... Good catch! – Stonz2 Jan 14 '15 at 15:01
1

I would wrap everything after the if(error) condition in an else statement (no sense in setting your response/json if the service failed). This will make sure that you're not trying to create objects with nil data that could cause issues. In your if statement that catches the error, you might also take this chance to let the calling method know that the service failed.

It's possible that the calling method is waiting for data to come back from this service. If it fails, the data will never come.

It's unclear whether or not this is being called on the main thread or not, as the calling method isn't shown. That being said, you really want to make sure that you hit web services from a background thread in order to keep your UI from freezing while it runs. I personally prefer dispatch_async but you can look into different ways of sending tasks to background threads.

Stonz2
  • 6,072
  • 4
  • 41
  • 60
  • Hey Thank you! Do you have any good examples of the method you prefer. Also I am calling the method within the `viewDidLoad` – David Biga Jan 13 '15 at 19:18
  • Here's a link to someone else asking about `dispatch_async` on SO: [Understanding dispatch_async](http://stackoverflow.com/questions/16283652/understanding-dispatch-async) The higher-voted answer shows where to place code that should run in the background, and then code that will be executed on the main thread (UI updates and such) after the background process has finished. – Stonz2 Jan 13 '15 at 21:55