在-init方法中直接设置ivars(不使用访问器)的EXC_BAD_ACCESS,为什么?

lms*_*lms 2 iphone cocoa properties objective-c

我花了大约10个小时试图找到这个导致我的应用程序崩溃的错误,这是我看到的最后一个地方(好吧它本来就是,但最后一个地方我曾预料到它).

最初我以为我有内存管理问题(不平衡的保留/释放),因为每次我发送-removeAllObjectsNSMutableArray填充我的自定义对象时都会发生崩溃.第一次-removeAllObjects调用时不会发生崩溃.我可以清除一次数组,重新填充它,然后在第二次清除时,我会得到一个EXC_BAD_ACCESS.这是我的数组在第一个"循环"中填充了3个对象,而在第二个"循环"中再次填充了3个.当我在每个循环中仅在阵列中存储1个对象时,需要4个周期才能崩溃(在第4次调用时-removeAllObjects).

我终于意识到,如果我更改了-init自定义对象的方法,崩溃就会消失.这是-init实施; 所有4周的ivars合成与性能(nonatomic, retain),所有类型的(NSString *)除了icon其是(NSNUmber *)

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

将其更改为此修复了错误:

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

我已经读过,不应该在-init方法中使用访问器,因为它可能会导致麻烦(例如,使用子类).

如果有人能向我解释为什么当我使用存取器时我的bug会消失,我会非常感激!说真的让我疯了,因为这个,直到昨晚凌晨5点.

bbu*_*bum 9

您正在直接分配但不保留实例变量.当您使用点语法时,您将触发retain合成属性的一部分,从而保留它们.

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

这应该可能解决问题(但是,我有点惊讶,我认为10仍然在NSNumber的实例缓存中.也许不是.).

从技术上讲,你也应该保留@""字符串,但是你可以不这样做,因为这样的字符串是一个特殊的套接字常量字符串,来自编译后的可执行文件(作为NSString的私有子类,覆盖不响应保留/释放/自动释放).

内存管理指南涵盖了这一点细节.对于任何刚接触平台的人,我建议每月重读一次(不,真的 - 交错编码,偶尔重新阅读文档会经常泄露出你没有足够经验的微妙细节之前.我仍然每半年重读一次基本指南.)