toom
toom

Reputation: 13316

iOS: sendSynchronousRequest with performSelectorInBackground

I need to make several https calls to a certain url. Therefore I do something like this

//ViewController Source
-(IBAction) updateButton_tapped {
    [self performSelectorInBackground:@selector(updateStuff) withObject:nil];
}


-(void) updateStuff {
    // do other stuff here...
    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.url]];
    [request setHTTPMethod:@"POST"];

    NSData *postData = [[Base64 encodeBase64WithData:payload] dataUsingEncoding:NSASCIIStringEncoding];
    [request setHTTPBody:postData];

    NSURLResponse* response = [[NSURLResponse alloc] init];
    NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

    //Process the recieved data...

    //Setup another synchronous request
    data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

    //Process data

    //do this another 4 times (note for loop cannot be use in my case ;) )

    //Finally update some view controllers
    [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationIdentifier" object:self];
}

So the problem with this code is that it crashes randomly (not always but frequently). I get no debugging output on the log. Sometime my whole app freezes or it simply crashes the whole program. But it never crashes if I run it on the main thread. Therefore I think the code is correct and I suppose now that it has something to do with the threading on the iphone.

What problems could happen when running the code this way and what might cause a random crashes?

Upvotes: 2

Views: 1959

Answers (3)

Jason Coco
Jason Coco

Reputation: 78343

The controllers or whatever are probably assuming they're receiving notifications on the main thread, which in your case they're not (and that's never a safe assumption to make). Have the controllers dispatch back to the main thread in their notification callbacks before they do anything with the data/updating the UIKit stuff, etc.

You should also put an @autorelease block around your entire implementation of -updateStuff.

Here's an example of a callback notification you might receive in one of your controllers:

- (void)updateStuffNotificaiton:(NSNotification*)note
{
  // Can't assume we're on the main thread and no need to
  // test since this is made async by performSelectorInBacground anyway
  dispatch_async(dispatch_get_main_queue(), ^{
    // relocate all your original method implementation here
  });
}

Also note that if your implementation of -updateStuff is creating and manipulating data structures that your notification callback methods then access, it is important to properly guard those accessors. It's often better to pass the data wholesale back to the callbacks in the notification's userInfo dictionary.

An example of adding the autorelease notation to your -updateStuff method:

-(void) updateStuff
{
 @autoreleasepool {
    // do other stuff here...
    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.url]];
    [request setHTTPMethod:@"POST"];

    // rest of method snipped for brevity

    //Finally update some view controllers
    [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationIdentifier" object:self];
 }
}

Upvotes: 0

iDifferent
iDifferent

Reputation: 2200

Memory Management, you don't release your request or response objects after allocation.

Upvotes: 1

Nickolay Olshevsky
Nickolay Olshevsky

Reputation: 14160

Please re-check your code so you don't update any GUI in background thread. Also, it should be much better to use asynchronous processing.

Upvotes: 0

Related Questions