【问题标题】:What is NSString in struct?结构中的 NSString 是什么?
【发布时间】:2009-12-29 06:15:54
【问题描述】:

我已经定义了一个结构并且想要将它的一个值分配给一个 NSMutableDictionary。当我尝试时,我得到一个 EXC_BAD_ACCESS。代码如下:

//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,为什么字典会有这样的问题呢?

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

此编辑基于以下一些 cmets。

问题似乎出在结构内存分配中。正如其中一个 cmets 所述,我在 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 = 日期;

所以内存问题很可能在我发布格式化程序时出现。日期变量没有保留。我应该这样做吗

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

这确实有效,但我留下了内存泄漏。

【问题讨论】:

  • EXC_BAD_ACCESS 与取消引用已释放对象(或未初始化对象)有关。你确定你初始化了myDictionary还是没有释放myStruct
  • 我已经在这方面更新了 OP。请在“编辑”条目后查看
  • 请注意,如果您使用 ARC,Objective-C 对象在结构或联合中是被禁止的

标签: iphone objective-c cocoa-touch struct


【解决方案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);

希望对您有所帮助。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      尝试让僵尸检查你在哪里过度释放物体。项目 -> 编辑活动可执行文件 -> 参数选项卡 -> 添加变量 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"];
      }
      

      【讨论】:

      • 谢谢。当我在调试窗口中打开结构时,我只看到 NSZombieEnabled 信息。它没有给出任何关于这发生在哪里的迹象。你对我如何追踪它有什么建议吗?
      【解决方案4】:

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

      有没有办法判断值是什么 aStruct.valueOne 是什么?

      嗯,调试器在你建立值的那一刻,应该能够接受定义并向你显示字面值;它应该知道 0xf41850 处的内存空间映射到一个 NSString 类,这是一个具有一定长度的字节数组,并且该地址处的字节以某种方式编码,因此应该映射到一些可以显示的字符串您在调试器中的显示。然而,后来,不,系统对那个空间包含什么没有(有效的)想法,因为它可以包含任何东西。

      因此,当您遇到 EXEC BAD ACCESS 时,这意味着您没有保留该值足够长的时间,因为您没有故意保留它,或者已经释放它(故意或无意地让系统释放它)。

      【讨论】:

        猜你喜欢
        • 2016-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多