2009-12-29 68 views
0

我已经定义了一个结构,并且想将它的一个值赋给一个NSMutableDictionary。当我尝试时,我得到一个EXC_BAD_ACCESS。下面是代码:什么是结构中的NSString?

//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 

这是在调试器控制台输出:

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

有没有办法告诉什么aStruct.valueOne的价值是什么?

既然是NSString,为什么字典有这样的问题呢?

-------------编辑-------------

此编辑基于下面的一些评论。

该问题似乎出现在结构内存分配中。正如其中一条评论所述,我没有将结构值赋给viewDidLoad中的字典的问题。问题是,后来我遇到了一个关于结构的问题。就在错误之前,我做的:

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. 

这只是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 =日期;

所以内存问题最有可能在我发布格式化程序。日期var没有保留。我应该做的

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

哪些工作,但然后我留下了内存泄漏。

+0

EXC_BAD_ACCESS与取消引用解除分配的对象(或未初始化的对象)有关。你确定你初始化了'myDictionary'还是没有释放'myStruct'? – notnoop 2009-12-29 06:28:15

+0

我已经更新了OP。请在“编辑”条目后查看 – 4thSpace 2009-12-29 07:53:46

+0

请注意,如果使用ARC Objective-C对象在结构或联合中被禁止 – elitalon 2013-01-23 17:47:56

回答

1

我重新创建了你的代码,并把NSDictionary的setValue方法放在aStruct.valueOne = @“firstValue”行的下面。它完美无缺地工作。所以,你的问题不在NSString中,但是其中一个对象(aStruct或myDictionary)会在某个地方被取消分配。你可以尝试以下方法:

static myStruct aStruct; 

要打印aStruct.valueOne的值,你可以使用:

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

此外,您还可以检查myDictionary的保留计数,看它是否仍被分配。但是,试图检查已经释放的对象的保留计数将导致错误。但它会在错误日志中告诉你,该对象已被释放。

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

希望有帮助。

1

不知道它为什么会崩溃,但不是p,而是使用po,它将打印NSString的内容或任何NS/CF对象的描述。

1

尝试启用僵尸来检查你在哪里过度释放对象。项目 - >编辑主动可执行文件 - >参数选项卡 - >添加变量NSZombieEnabled并赋值YES。 (并将复选框设置为YES)。

然后,您应该在跟踪中获得有关您的错误的更多信息。

不要忘记关闭NSZombieEnabled复选框。

编辑:

当您将valueOne

aStruct.valueOne = @"firstValue"; 

实际上创建NSString对象,并把它放到自动释放池。因此,稍后当您尝试将该对象传递给您的字典时,它可能已被自动释放,这就是为什么您要获得EXC_BAD_ACCESS。当你为结构指定新的指针时,你必须实现一些方法来为你做内存管理。事情是这样的:

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

因此,在您viewDidLoad你必须使用你的新方法:

- (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"]; 
} 
+0

谢谢。当我在调试窗口中打开结构时,我只能看到NSZombieEnabled信息。它没有给出任何关于这种情况发生的迹象。你有什么建议可以追踪它吗? – 4thSpace 2010-04-19 00:21:47

0

任何“类*实例”是指向的对象。您看到的$1 = (NSString *) 0xf41850实际上是指向当前分配用于存放valueOne的内存空间的指针。通常与EXEC BAD ACCESS相关的问题是,内存空间不是永久分配来保存valueOne,并且稍后会被回收,通常在该方法执行完成后立即执行(称为垃圾回收)。然后,当你以后尝试访问它时,例如从一个不同的方法或甚至相同的方法,但在后续的执行中,系统说'嘿,该内存地址用于其他事情',它会引发Exec Bad Access错误。

有没有办法告诉什么aStruct.valueOne的价值 是什么?

好,调试器,此刻的你树立的价值,应该可以挑上的定义并向您显示字面值;它应该知道0xf41850处的内存空间映射到NSString类,它是一些长度为字节的数组,并且该地址处的字节以特定方式编码,因此应该映射成可以在调试器中显示的一些字符串。然而,后来呢,不,系统没有(有效的)关于这个空间包含的想法,因为它可以包含任何东西。因此,当您遇到EXEC BAD ACCESS时,这意味着您不会长时间保留该值,这可能是因为您没有故意保留它,或者已经释放它(有意或无意让系统释放它)。