views:

281

answers:

3

I've defined a struct and want to assign one of its values to a NSMutableDictionary. When I try, I get a EXC_BAD_ACCESS. Here is the code:

//in .h file
typedef struct {
NSString *valueOne;
NSString *valueTwo;
}  myStruct;

myStruct aStruct;

//in .m file
- (void)viewDidLoad {
[super viewDidLoad];
aStruct.valueOne = @"firstValue";
}

//at some later time
[myDictionary setValue:aStruct.valueOne forKey:@"key1"]; //dies here with EXC_BAD_ACCESS

This is the output in debugger console:

(gdb) p aStruct.valueOne
$1 = (NSString *) 0xf41850

Is there a way to tell what the value of aStruct.valueOne is?

Since it is an NSString, why does the dictionary have such a problem with it?

------------- EDIT -------------

This edit is based on some comments below.

The problem appears to be in the struct memory allocation. I have no issues assigning the struct value to the dictionary in viewDidLoad, as mentioned in one of the comments. The problem is that later on, I run into an issue with the struct. Just before the error, I do:

po aStruct.oneValue

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x9895cedb in objc_msgSend ()
The program being debugged was signaled while in a function called from GDB.
GDB has restored the context to what it was before the call.
To change this behavior use "set unwindonsignal off"
Evaluation of the expression containing the function (_NSPrintForDebugger) will be   abandoned.

This occurs just before the EXC_BAD_ACCESS:

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"MM-dd-yy_HH-mm-ss-A"];
NSString *date = [formatter stringFromDate:[NSDate date]];
[formatter release];

aStruct.valueOne = date;

So the memory issue is most likely in my releasing of formatter. The date var has no retain. Should I instead be doing

NSString *date = [[formatter stringFromDate:[NSDate date]] retain];

Which does work but then I'm left with a memory leak.

+1  A: 

I recreated your code and put the NSDictionary setValue method, right under the aStruct.valueOne = @"firstValue" line. It works perfectly without any error. So, your problem is not with the NSString, but with one of the objects (either aStruct or myDictionary) getting deallocated somewhere down the line. You can try the following:

static myStruct aStruct;

To print the value of aStruct.valueOne, you may use:

NSLog(@"aStruct.valueOne = %@ \n", aStruct.valueOne);

Also, you can check the retain counts of myDictionary to see if it is still allocated. However, trying to check for the retain count of an already deallocated object will result in an error. But it will tell you in the error log, that the object is already deallocated.

NSLog(@"Retain Count of myDictionary = %i \n", myDictionary.retainCount);

Hope that helps.

Prashant
+1  A: 

Not sure why it's crashing, but instead of p, use po and it will print the contents of the NSString or description of any NS/CF object.

Ken Aspeslagh
A: 

Try to enable zombies to check where do you over-release objects. Project -> Edit Active Executable -> Arguments tab -> Add variable NSZombieEnabled and assign it YES. (and set checkbox to YES).

Then you should get more info about your error in the trace.

Don't forget to disable NSZombieEnabled checkbox then.

EDIT:

When you assign a valueOne:

aStruct.valueOne = @"firstValue";

you actually create NSString object and put it into autorelease pool. So later when you try to get that object to pass it to your dictionary, it might be autoreleased already, that's why you are getting EXC_BAD_ACCESS. You have to implement some method which will do memory management for you when you assign new pointers to your struct. Something like this:

- (void)setValueOne:(NSString *)newValueOne {
   [aStruct.valueOne autorelease];
   aStruct.valueOne = [newValueOne retain];
}

So in your viewDidLoad you have to use your new method:

- (void)viewDidLoad {
   [super viewDidLoad];
   // make sure it is nil "on startup" because setValueOne: method will send autorelease method
   aStruct.valueOne = nil;
   aStruct.valueTwo = nil;
   [self setValueOne:@"firstValue"];
}
beefon
Thanks. I only see the NSZombieEnabled info when I open up the struct in the debug window. It doesn't give any indication about where this is happening. Do you have any suggestions on how I can track it down?
4thSpace