Question

I have implemented an NSURLConnection that sends a request to a server and receives some data back which is stored in an NSMutableData object. These are the methods that I implemented as part of NSURLConnectionDelegate:

-(void)upLoadBook:(NSMutableDictionary *)theOptions{

NSMutableString *theURL = [[NSMutableString alloc] initWithString:@"theURL"];

[theURL appendFormat:@"&Title=%@&Author=%@&Price=%@",  [theOptions objectForKey:@"bookTitle"], 
                                                       [theOptions objectForKey:@"bookAuthor"], 
                                                       [theOptions objectForKey:@"bookPrice"]];
[theURL appendFormat:@"&Edition=%@&Condition=%@&Owner=%@", [theOptions objectForKey:@"bookEdition"],
                                                        [theOptions objectForKey:@"bookCondition"],
                                                        _appDel.userID];

NSLog(@"%@\n", theURL);
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:theURL]
                                            cachePolicy:NSURLRequestUseProtocolCachePolicy
                                        timeoutInterval:10.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
    // Create the NSMutableData to hold the received data.
    // receivedData is an instance variable declared elsewhere.
    receivedData = [NSMutableData data];
}
}

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

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse      
  *)response
 {
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.

// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.

// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}

 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
   // do something with the data
  // receivedData is declared as a method instance elsewhere

//Receives a response after book has been uploaded (Preferably a Book ID...)
  responseString = [[NSString alloc] initWithData:receivedData         
 encoding:NSUTF8StringEncoding];

NSLog(@"Response String: %@", responseString);
[_options setValue:responseString forKey:@"bookID"];

[self performSegueWithIdentifier:@"UploadSuccessSegue" sender:self];

}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Whoops." message:@" No internet     
connection.\n Please make sure you have a connection to the internet." 
                                               delegate:self cancelButtonTitle:@"Ok"   
otherButtonTitles: nil];
[alert show];
}

The function uploadBook seems to be called,however, I never get to didFinishLoading and didReceiveData never receives any data. What could be a possible problem. Any hints or clues would be much appreciated.

Was it helpful?

Solution

You need to add your NSURLConnection to the current run loop or a separate one (such as one you set up in a separate thread). The delegate methods do need to get CPU time, after all.

Looking at this related question's accepted answer, it can also be done via Grand Central Dispatch:

dispatch_async(dispatch_get_main_queue(), ^{
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
    [conn start];
});

OTHER TIPS

One thing for sure is that you should %-escape your list of parameter before trying to send the request.

You can use stringByAddingPercentEscapesUsingEncoding for that purpose:

NSMutableString *theURL = [[NSMutableString alloc] initWithString:@""];

[theURL appendFormat:@"&Title=%@&Author=%@&Price=%@",  [theOptions objectForKey:@"bookTitle"], 
                                                   [theOptions objectForKey:@"bookAuthor"], 
                                                   [theOptions objectForKey:@"bookPrice"]];
[theURL appendFormat:@"&Edition=%@&Condition=%@&Owner=%@", [theOptions objectForKey:@"bookEdition"],
                                                    [theOptions objectForKey:@"bookCondition"],
                                                    _appDel.userID];


 theURL = [NSStringWithFormat:@"YOUR_URL_HERE?",[theURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

Please, note that I refactored your code with the minimum number of changes to get the result. You can find better refactorizations for sure.

Here is a sample that works from one of my projects:

NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://www.brayden.me/analytics/device.php"]];
[urlRequest setHTTPMethod:@"POST"];

NSMutableString *postParams = [NSMutableString string];
[postParams appendFormat:@"session=%@&", analyticsSession];
[postParams appendFormat:@"device=%@&", device];
[postParams appendFormat:@"system=%@&", csystem];
[postParams appendFormat:@"version=%@&", version];
[postParams appendFormat:@"launch=%f&", totalLaunchTime];

if([Analytics_Location location].latitude && [Analytics_Location location].longitude) {
    [postParams appendFormat:@"latitude=%@&", [Analytics_Location location].latitude];
    [postParams appendFormat:@"longitude=%@&", [Analytics_Location location].longitude];
}

[urlRequest setHTTPBody:[postParams dataUsingEncoding:NSUTF8StringEncoding]];

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:YES];
[connection start];

Make sure your header method also uses . The code of mine should at least show you how to properly format the request, as I can verify this does receive data from a PHP call of mine.

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