我花了大约10个小时试图找到这个导致我的应用程序崩溃的错误,这是我看到的最后一个地方(好吧,它本来是,但最后一个地方,我曾预料到它)。
最初我以为我有内存管理问题(不平衡的保留/释放),因为每次我发送-removeAllObjects
到填充了我的自定义对象的NSMutableArray
时都会发生崩溃。第一次调用-removeAllObjects
时不会发生崩溃。我可以清除一次数组,重新填充它,然后在第二次清除时,我会得到一个EXC_BAD_ACCESS。这是我的数组在第一个“循环”中填充了3个对象,而在第二个“循环”中再次填充了3个。当我在每个周期中只在阵列中存储1个对象时,需要4个周期才能崩溃(在-removeAllObjects
的第4个调用中)。
我终于意识到,如果我更改了自定义对象的-init
方法,崩溃就会消失。这是-init
实现;所有4个ivars都是合成属性(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;
}
我已经读过,不应该使用-init
方法中的访问器,因为它会导致麻烦(例如,使用子类化)。
如果有人能够向我解释为什么当我使用访问器时我的bug会消失,我会非常感激!说真的让我疯了,因为这个,直到昨晚凌晨5点。
答案 0 :(得分:9)
您正在直接分配但不保留实例变量。当您使用点语法时,您将触发合成属性的retain
部分,从而保留它们。
-(id)init {
if (self = [super init]) {
ip = @"";
mac = @"";
vendor = @"";
icon = [[NSNumber numberWithInt:0] retain];
}
return self;
}
这应该可能解决问题(但是,我有点惊讶,我认为10仍然在NSNumber的实例缓存中。也许不是。)。
从技术上讲,你也应该保留@“”字符串,但是你可以不这样做,因为这样的字符串是一个特殊的套接字常量字符串,来自编译后的可执行文件(作为NSString的私有子类,它不会覆盖到回应保留/释放/自动释放)。
memory management guide详细介绍了这一点。对于任何刚接触平台的人,我建议每月重读一次(不,真的 - 交错编码,偶尔重新阅读文档会经常发现你没有足够经验的微妙细节之前。我仍然每半年重读一次基本指南。)