代码之家  ›  专栏  ›  技术社区  ›  lmirosevic

在-init方法中直接设置ivar(不使用访问器)时,exc_bad_access,为什么?

  •  2
  • lmirosevic  · 技术社区  · 14 年前

    我花了大约10个小时的时间去寻找这个导致我的应用崩溃的bug,它就在我最后一次看到的地方(很可能是,但也是我最不希望看到的地方)。

    最初我认为我有内存管理问题(不平衡的保留/释放),因为每次发送时都会发生崩溃。 -removeAllObjects NSMutableArray 填充了我的自定义对象。车祸不会第一次发生的 -删除所有对象 被呼叫。我可以清除一次数组,重新填充它,然后在第二次清除时,我将获得一个exc_bad_u访问。这是我的数组在第一个“循环”中填充了3个对象,在第二个“循环”中填充了3个对象。当我在每个循环中仅在数组中存储1个对象时,崩溃需要4个循环(在 -删除所有对象 )

    我终于意识到,如果我改变了 -init 自定义对象的方法。这是 -初始化 实现;所有4个IVAR都具有 (nonatomic, retain) ,所有类型 (NSString *) 除了 icon 这是一个 (NSNUmber *)

    -(id)init {
        if (self = [super init]) {
            ip = @"";
            mac = @"";
            vendor = @"";
            icon = [NSNumber numberWithInt:0];
        }
        return self;
    }
    

    把它改成这个,修复了这个错误:

    -(id)init {
        if (self = [super init]) {
            self.ip = @"";
            self.mac = @"";
            self.vendor = @"";
            self.icon = [NSNumber numberWithInt:0];
        }
        return self;
    }
    

    我已经读到,一个人不应该在 -初始化 方法,因为它会导致问题(例如子类化)。

    如果有人能向我解释为什么当我使用存取器时我的错误会消失,我会非常感激!说真的,这让我抓狂了,因为这件事一直到昨晚5点。

    1 回复  |  直到 14 年前
        1
  •  9
  •   bbum    14 年前

    您正在直接分配但不保留实例变量。使用点语法时,将触发 retain 部分合成性质,因此,保留它们。

    -(id)init {
        if (self = [super init]) {
            ip = @"";
            mac = @"";
            vendor = @"";
            icon = [[NSNumber numberWithInt:0] retain];
        }
        return self;
    }
    

    这很可能解决了问题(不过,我有点惊讶,我认为10仍然在nsnumber的实例缓存中。也许不是。

    从技术上讲,您还应该保留@“”字符串,但您可以避免这样做,因为这样的字符串是从编译的可执行文件中产生的特殊大小写常量字符串(作为nsstring的私有子类,重写以不响应retain/release/autorelease)。

    这个 memory management guide 详细介绍了这一点。对于平台新手来说,我建议每个月重读一次(不,真的——偶尔重读一下文档,会发现一些微妙的细节,这些细节你以前没有足够的经验去摸索。我 仍然 每半年重新阅读基本指南。)