Jacksonkr
Jacksonkr

Reputation: 32207

ios ARC table bad access

for my table view I have the following going on (paraphrased)

.h

@interface OptionsView : UIView <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, retain) NSArray *dataSource;

.m

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {

        ...

        self.dataSource = [NSArray arrayWithObjects:options, sections, sponsor,  nil];
    }
    return self;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(self.dataSource) {
        NSArray *ds = [self.dataSource objectAtIndex:indexPath.section];
        NSDictionary *d = [ds objectAtIndex:indexPath.row];
        ActionBlock a = [d objectForKey:ACTION]; // <-- Thread 1: EXC_BAD_ACCESS (code=2, address=0x802)
        if(a != nil) a();
    }
}

You can see that in my didSelectRowAtIndexPath I'm getting an EXC_BAD_ACCESS but I'm not sure why. Because I'm using arc it isn't a zombie problem (already checked).

Using breakpoints I see that the self.dataSource exists after it's initialized, but not later when it's needed. It doesn't show up as <nil> either, it's just white space. Also, this works in debug but not in release so what does that mean?

** EDIT adding a screenshot **

You will notice that neither ds or d show up.. odd? xcode debug

Upvotes: 1

Views: 463

Answers (2)

Aaron Hayman
Aaron Hayman

Reputation: 8502

So there's two places I can see that might cause the problem. First, what is ACTION? Is it some sort of NSString? Just want to make sure that you're using a valid key object. Second, (and more likely the problem), it looks like ActionBlock is some kind of code block you're storing in a collection array. Are you copying that block before you store it in the array/dictionary? You must copy any block you intend on keeping around (storing) longer than the scope it was created in. This is easy to do. For example:

void (^NewBlock)(void) = [^{
    ....code....
} copy];

Alternately:

void (^NewBlock)(void) = ^{
    ....code....
};

[dictionary setObject:[NewBlock copy] forKey:ACTION]; //Assuming #define ACTION @"action"

This copies it onto the heap so that it can be stored. If you don't copy it, you'll get BAD_EXC_ACCESS anytime you try to reference the block outside the scope it was created in.

Upvotes: 2

Marcal
Marcal

Reputation: 1371

It seems you´re using a UIViewController instead of a UITableViewController. If I remember correctly, you have to go to the inspector and drag the delegate and datasource from the tableView to the UIViewController. I don´t remember exactly and I´m not on my computer but I´m sure I did it several times before I began to use a UITableViewController for every tableView I have.

Oh, and i wouldn´t use dataSource as a name for your array. Just to prevent naming conflicts.

Upvotes: 0

Related Questions