2

I'm using AFNetworking to make a web request. After the web request completes. I want a UIAlertView to be shown. I'm using ARC and the code seems to work on devices. If I use a simulator I get an error: EXC_BAD_ACCESS

What am I doing wrong?

UIAlertView* postSubmitAlertView = [[UIAlertView alloc] init];
postSubmitAlertView.delegate = self;
[postSubmitAlertView addButtonWithTitle:@"Ok"];

AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] 
    initWithRequest:request];

[op setCompletionBlock:^(void) {
    if(op.response.statusCode == 200) {

        postSubmitAlertView.title = @"Submission Good";
        postSubmitAlertView.message = @"GOOD";

   } else {

        postSubmitAlertView.title = @"Submission Failed.";
        postSubmitAlertView.message = @"FAIL";
   }

   [postSubmitAlertView show];
}];
[op start];
mmattax
  • 27,172
  • 41
  • 116
  • 149

3 Answers3

4

The key problem is that UIKit stuff should be called on the main thread.

Note: For the most part, UIKit classes should be used only from an application’s main thread. This is particularly true for classes derived from UIResponder or that involve manipulating your application’s user interface in any way.

UIKit Framework Reference

Looking at the docs for NSOperation under setCompletionBlock:

Discussion The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it.

The simplest solution to modify your code is to call the UIKit stuff on the main thread

- (void)viewDidLoad
{
  [super viewDidLoad];

  NSURL *URL = [NSURL URLWithString:@"http://www.google.com"];
  NSURLRequest *request = [NSURLRequest requestWithURL:URL];

  AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc]
                                initWithRequest:request];

  [op setCompletionBlock:^(void) {

    dispatch_async(dispatch_get_main_queue(), ^{
      UIAlertView* postSubmitAlertView = [[UIAlertView alloc] init];
      postSubmitAlertView.delegate = self;
      [postSubmitAlertView addButtonWithTitle:@"Ok"];

      if(op.response.statusCode == 200) {

        postSubmitAlertView.title = @"Submission Good";
        postSubmitAlertView.message = @"GOOD";

      } else {

        postSubmitAlertView.title = @"Submission Failed.";
        postSubmitAlertView.message = @"FAIL";

      }

      [postSubmitAlertView show];
    });

  }];
  [op start];
}
Paul.s
  • 38,494
  • 5
  • 70
  • 88
1

The EXC_BAD_ACCESS is caused by accessing a released object. To avoid this make your call to UIAlertView kind of modal:

//Function body:

-(void)checkSaving
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Do you want to add these results to your database?"
                                                    message:@"\n\n"
                                                   delegate:self
                                          cancelButtonTitle:@"No"
                                          otherButtonTitles:@"Save", nil];
    alert.alertViewStyle = UIAlertViewStyleDefault;
    [alert show];

    //this prevent the ARC to clean up :
    NSRunLoop *rl = [NSRunLoop currentRunLoop];
    NSDate *d;
    d = (NSDate*)[d init];
    while ([alert isVisible]) {
        [rl runUntilDate:d];
    }
}

//Your choice result:

- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    // the user clicked one of the OK/Cancel buttons
    if (buttonIndex == 1)//Save
    {
        //do something    
    }
    if (buttonIndex == 0)//NO
    {
        //do something
    }
}

//Register the functions in the interface declaration:

@interface yourViewController ()
-(void)checkSaving
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
//...
@end


//To call:

[self checkSaving];

I wish this will help you.

Community
  • 1
  • 1
araferna
  • 71
  • 1
  • 5
0
UIAlertView* postSubmitAlertView = [[UIAlertView alloc] init];
postSubmitAlertView.delegate = self;
[postSubmitAlertView addButtonWithTitle:@"Ok"];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];
[operation  setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        NSLog(@"success: %@", operation.responseString);   
        postSubmitAlertView.title = @"Submission Good";
        postSubmitAlertView.message = @"GOOD";

} 
    failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"error: %@",  operation.responseString);
        postSubmitAlertView.title = @"Submission Failed.";
        postSubmitAlertView.message = @"FAIL";

}
 ];

[postSubmitAlertView show];

Hope this will solve your problem.

Kamleshwar
  • 2,967
  • 1
  • 25
  • 27