views:

28

answers:

2

Hi all, I decided to get back to Cocoa/Objective-C programming recently and my current project calls for an NSTableView.

I thought I had gotten the process down to a Science but it appears I was wrong. I am getting an EXE_BAD_ACCESS error in the datasource method that actually returns the data.

When I run the application, all results show up on the NSTableView but shortly after, the EXE_BAD_ACCESS occurs. Occasionally, and seemingly randomly, the EXE_BAD_ACCESS error will not be thrown and instead I will get various errors in the console like the one below:

-[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x10011b780

Afterwards, the interface becomes mostly unresponsive.

From various debug messages I have been able to predict that an error is occurring because the method is being called with a row integer that is greater than the data NSArray's count. Is my Mac screwing up or am I doing something wrong? Below is my code and any help would be appreciated. Thank you!

Header File (TableViewController.h)

#import <Cocoa/Cocoa.h>


@interface TableViewController : NSObject {
    IBOutlet NSTableView *tableView;

    NSArray *componentArray;
}

@end

Main File (TableViewController.m)

#import "TableViewController.h"


@implementation TableViewController

- (void) awakeFromNib {
    NSString *components = @"Test:Test2:Test3";
    componentArray = [components componentsSeparatedByString:@":"];

    [tableView setDataSource:self];
    [tableView reloadData];
}

- (int)numberOfRowsInTableView:(NSTableView *)tableView {
    return [componentArray count];
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
    // EXE_BAD_ACCESS is occuring here
    return [componentArray objectAtIndex:row];
}

@end
+2  A: 
componentArray = [components componentsSeparatedByString:@":"];

The -componentsSeparatedByString: method returns an -autoreleased array. Therefore, by the time it is needed, the componentArray may no longer be valid.

You need to -retain it explicitly.

componentArray = [[components componentsSeparatedByString:@":"] retain];

(of course, make sure to -release the array in -dealloc. Or just turn on Garbage Collection and forget about memory management.)

KennyTM
Thank you. That seems to have fixed the problem! Strange, I never remember having to do that before, though. Anyway, thanks again for the quick response.
Jesse
Jesse: It's because you're creating the array in `awakeFromNib` and using it significantly later (where by “significantly” I mean “not in the same autorelease pool”). This isn't a problem when you're just assigning to a local variable; it's a problem here because you're storing it in an instance variable (as you need to in order to create it in `awakeFromNib` and use it in your data source methods). You can use the Zombies instrument in Instruments to debug this sort of thing.
Peter Hosey
+1  A: 

Retain componentArray once you have it populated, then do the requisite release in dealloc.

Philip Regan
Thank you for the quick response! I got it working!
Jesse
How about accepting the answer to give Philip credit for taking the time to help you? Maybe give KennyTM an upvote for coming in a close second? Karma is important on SO.
Joshua Nozzi