【问题标题】:Crash when accessing a NSMutableArray member variable访问 NSMutableArray 成员变量时崩溃
【发布时间】:2011-09-02 07:08:04
【问题描述】:

我在使用 NSMutableArray 时遇到了一些问题。我确定我在分配 NSMutableArray 时做错了,但作为 iPhone 新手,这对我来说并不明显。当我运行下面的代码时,我可以将对象 MyObject 添加到数组 objects_ 并设置名称等。NSLog 显示正确的数据。

但是当我尝试从函数 printObject 访问 objects_ 成员时,我得到了一个 SIGABRT。看起来内存已被释放或什么?

任何帮助表示赞赏。


@interface MyObject : NSObject {
    NSString *name;
}

-(void) SetName:(NSString*) name_str;
-(NSString*) GetName;

@end

@interface ObjectListViewController : UITableViewController {
    NSMutableArray* objects_;
}

-(void) initTableData;

@end

@implementation ObjectListViewController

- (void)initTableData {
    objects_ = [[NSMutableArray alloc] initWithCapacity:10];
    MyObject *obj = [MyObject alloc];
    [obj SetName:@"Test"];
    [objects_ addObject:obj];

    MyObject* testObj = (MyObject*)[objects_ objectAtIndex:0];
    NSLog([testObj GetName]);
}

- (void)printObject {
    MyObject* testObj = (MyObject*)[objects_ objectAtIndex:0];
    NSLog([testObj GetName]);
}

【问题讨论】:

  • 好吧,对于初学者来说,你永远不会在@interface 中定义 printObject。
  • 此代码看起来不错,因此您缺少问题代码。您确定 initTableData 正在被调用吗?在调用printObject 之前,还有什么可能触及objects_ 吗? SIGABRT 是不寻常的,尤其是在控制台中没有消息的情况下。这不是一个糟糕的选择器,也不是一个空数组,两者都会输出有用的调试信息。
  • @quixoto:代码看起来不太好。他从不初始化 obj。
  • @JeremyP:是的。连同您在回答中提到的所有其他要点。不过,它们都没有解决 SIGABRT 的奥秘。 :) 当然,除非——我现在愿意打赌就是这种情况——调试控制台中有一些有用的信息,OP 没有与我们共享。

标签: iphone objective-c


【解决方案1】:

我们可以消除在 MyObject 上缺少初始化调用作为崩溃的原因,因为在这种情况下它将是良性的。在 NSObject 上调用 init 只会返回 self,因此在这种情况下调用它不会改变行为。所以我不认为这里的前两个答案会有所不同:

一个对象在初始化之前还没有准备好使用。 NSObject 类中定义的 init 方法不进行初始化;它只是返回自我。

Chuck 正确指出 initobject allocation and initialization 中的一个基本步骤,您应该在分配 MyObject 时调用它。

我也不确定第三个答案是否正确。我真的不明白在 objects_ 数组上添加合成会有什么不同。你还没有将它定义为一个属性,我真的不明白你为什么需要,因为它只是类内部的数据。

对问题的评论好吧,对于初学者来说,你永远不会在@interface 中定义 printObject。eykanal 对你也没有真正的帮助,因为你必须在内部调用 printObject,否则你不会撞到崩溃。

通读代码,我看不到明显的错误。 initTableData 完成后 objects_ 上的保留计数应该是 1,MyObject 实例上的保留计数也应该是 1。所以我认为一定有其他代码在其他地方发布objects_

我假设它在 objectAtIndex 调用上崩溃了?控制台中是否有任何信息?调用堆栈是什么样的?

【讨论】:

  • 是的,我必须同意 init 是不必要的。为此 +1
  • init 在这种特殊情况下是否执行有用的功能,语言仍然需要它。你可能是对的,这不是罪魁祸首,但说“你不需要打电话给init”仍然是错误的(而且,这是评论,而不是答案)。所以 -1 用于传播不准确的信息。 developer.apple.com/mac/library/documentation/Cocoa/Conceptual/…
  • @Chuck 我以为我已经用“尽管这是很好的做法,您可能想在 MyObject init 中做一些事情”来澄清这句话。我正在消除缺少 init 作为崩溃的原因,我认为这是有效的。但是,我会尝试澄清这一点。
【解决方案2】:
 MyObject *obj = [MyObject alloc];

应该是:

 MyObject *obj = [[MyObject alloc] init];

【讨论】:

    【解决方案3】:
        @interface ObjectListViewController : UITableViewController {
            NSMutableArray* objects_;
        }
    
       @property (nonatomic, retain) NSMutableArray *objects_;
       -(void) initTableData;
       -(void) printObject;
    
        @end
    

    在实现中添加合成

    @implementation ObjectListViewController
    @synthesize objects_;
    

    【讨论】:

    • 好主意,但不是问题。
    【解决方案4】:

    以下是您的代码中的一些问题:

    • 您永远不会初始化您的 MyObj 对象。虽然它直接继承自 NSObject 并且 NSObject 被记录为除了返回自身之外什么都不做,但你永远不知道幕后是否发生了其他事情,所以把它放进去只是为了消除这种可能性。
    • 您的方法不遵循正常的命名约定。方法名称应以小写字母开头,“get”应仅在通过参数通过引用传回数据时使用,例如NSData-getBytes:长度:。你的 getter 和 setter 应该分别是 -name 和 -setName:。这似乎是一个小问题,但如果您以后开始使用 KVO 和 KVC,它将对您有所帮助。
    • 永远不要 NSLog(someStringVariable) 总是 NSLog(@"%@", someStringVariable)。正如你现在所拥有的,如果对象的名称包含百分比格式序列,例如%@、%d、%s 等,您的程序将在 NSLog 上崩溃。但是,这不是您当前问题的原因 - 它会在 -initTableData 中的 NSLog 上崩溃
    • 您不需要转换 -objectAtIndex 的结果:

    说了这么多,我看不出有什么会导致您遇到的特定问题。可能是 MyObject 中名称的 getter 或 setter 不正确。请张贴。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 2015-12-22
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      相关资源
      最近更新 更多