Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPhone EXC_BAD_ACCESS when using blocks

Im trying to create a simple callback using blocks. I have a MainViewController which addSubView another DatePickerViewController.view i created a block like this

typedef void(^DateChangedBlock)(NSDate*);

And i have a method on my DatePickerViewController called

setOnDateChangedCallback:(DateChangedBlock)callback

I store the callback in a property of the DatePickerViewController. The DatePickerViewController's view is a UIDatePicker instance, ive bound an IBAction to the value changed to a method that does this.

- (IBAction)dateChanged:(id)sender {

    if (dateChangedCallback != nil)
    {
        dateChangedCallback(nil);
    }
}

Here is how i register the block in the MainViewController

DatePickerViewController *dateController = [[DatePickerViewController alloc] initWithNibName:@"DatePickerView" bundle:nil];

self.datePicker = dateController;
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 100, 200)];
[self.view addSubview:textView];
DateChangedBlock myBlock = ^(NSDate *newDate) {
 textView.text = @"testing";
};

[self.datePicker setOnDateChanged: myBlock];
[self.datePicker dateChanged:self]; // force trigger (this works).

When i force trigger the dateChanged method on the DatePickerViewController it works no problem. But when the datepicker itself triggers the method thru the IBAction i get a EXC_BAD_ACCESS error. The error occurs in this method on the "int retVal" line.

#import <UIKit/UIKit.h>

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil); // THREAD 1: program received EXC_BAD_ACCCESS.**
    [pool release];
    return retVal;
}

What am i doing wrong?

like image 446
Mads Lee Jensen Avatar asked Mar 13 '11 12:03

Mads Lee Jensen


2 Answers

You should copy your block when passing it to other method (such as attribute setter in your situation). So when setting the callback block do this:

[self.datePicker setOnDateChanged:[[myBlock copy] autorelease]];

You get the EXC_BAD_ACCESS cause block's variables used when creating the block don't get retained by the block itself. So when calling the block - variables do not exist anymore.

like image 77
Eimantas Avatar answered Nov 10 '22 04:11

Eimantas


The accepted answer is wrong. You don't need to copy it in your MainViewController. Rather, the setOnDateChangedCallback: method which takes a block argument is responsible for copying it if it needs to store it in an instance variable (which I see it is doing, in the variable dateChangedCallback that is later used by another method). If dateChangedCallback is a synthesized property, you can accomplish this by declaring the property as copy instead of retain.

like image 4
user102008 Avatar answered Nov 10 '22 03:11

user102008