我有一个无法理解的内存泄漏问题!观看这个初始化方法:
- (id)initWithNomeCompositore:(NSString *)nomeCompositore nomeOpera:(NSString *)nomeOpera {
if (self = [super init]) {
NSString *pathOpere = [[NSBundle mainBundle] pathForResource:kNomeFilePlistOpere ofType:kTipoFilePlist];
NSDictionary *dicOpera = [NSDictionary dictionaryWithDictionary:
[[[NSDictionary dictionaryWithContentsOfFile:pathOpere]
objectForKey:nomeCompositore]
objectForKey:nomeOpera]];
self.nomeCompleto = [[NSString alloc] initWithString:nomeOpera];
self.compositore = [[NSString alloc] initWithString:nomeCompositore];
self.tipologia = [[NSString alloc] initWithString:[dicOpera objectForKey:kKeyTipologia]];
}
return self;}
然后这个小变化(注意self.tipologia):
- (id)initWithNomeCompositore:(NSString *)nomeCompositore nomeOpera:(NSString *)nomeOpera {
if (self = [super init]) {
NSString *pathOpere = [[NSBundle mainBundle] pathForResource:kNomeFilePlistOpere ofType:kTipoFilePlist];
NSDictionary *dicOpera = [NSDictionary dictionaryWithDictionary:
[[[NSDictionary dictionaryWithContentsOfFile:pathOpere]
objectForKey:nomeCompositore]
objectForKey:nomeOpera]];
self.nomeCompleto = [[NSString alloc] initWithString:nomeOpera];
self.compositore = [[NSString alloc] initWithString:nomeCompositore];
self.tipologia = [[NSString alloc] initWithString:@"Test"];
}
return self;}
在第一个变种中产生了内存泄漏,第二个不是!我只是不明白为什么!仪器证明了内存泄漏,强调了这一行:
[NSDictionary dictionaryWithContentsOfFile:pathOpere]
这是dealloc方法:
- (void)dealloc {
[tipologia release];
[compositore release];
[nomeCompleto release];
[super dealloc];}
答案 0 :(得分:1)
请记住,alloc
会返回您拥有的对象。
如果您将三个字符串属性声明为retain
,则将这些对象分配给您的属性意味着您现在拥有每个属性两次,因为您已将其分配,并且因为您已将其分配给您的属性。对象仍然存活,因为没有任何东西释放他们的第二个所有权。
如果您将属性声明为copy
(这是声明NSString属性的正确方法),则分配对象会将副本存储为属性的值。你没有对原始对象做任何进一步的处理,因为没有任何东西会释放它们。
无论哪种方式,这都是你的泄密。
该属性应声明为copy
;如果已经存在,请不要尝试通过改变它来修复泄漏。
您不应在此处使用属性访问权限。请记住,分配给属性是set<PropertyName>:
消息,并且您的对象尚未完全初始化。将消息发送到未完全初始化或未完全解除分配的对象会引发麻烦,特别是涉及子类时,因为它们可能会以超类不期望的方式覆盖访问器方法。
因此,仅在init
中,直接分配给实例变量。仅在dealloc
中,将release
消息直接发送到实例变量中的对象。在其他地方,使用属性访问。
您也不应在此使用alloc
和initWithString:
。它会起作用,但惯例是将copy
消息发送到您已有的对象,与属性相同。将copy
消息发送到输入字符串对象,然后将副本分配给实例变量。
当您使用属性访问时,请使用便捷构造函数(例如stringWith…:
),因为这些返回您不拥有的对象。当您将这些对象分配给copy
- 声明的属性时,您实际上将存储您拥有的副本。
另一种方法是使用alloc
和initWithWhatever:
,然后立即autorelease
该对象,然后再将其分配给该属性;这种方式会创建一个您拥有的对象,然后在将其分配给属性之前立即放弃所有权。
答案 1 :(得分:0)
尝试
nomeCompleto = [[NSString alloc] initWithString:nomeOpera];
compositore = [[NSString alloc] initWithString:nomeCompositore];
tipologia = [[NSString alloc] initWithString:[dicOpera objectForKey:kKeyTipologia]];
或
self.nomeCompleto = nomeOpera;
self.compositore = nomeCompositore;
self.tipologia = [dicOpera objectForKey:kKeyTipologia];
而不是self.xxx = [[yyy alloc] init...]
。
在原始代码中,赋值的RHS返回保留计数+1的对象,如果@property
具有(retain)
或(copy)
,则最终保留计数将为是+2。因此,即使您在-dealloc
中释放它们,净保留计数为+1,也会导致内存泄漏。
+dictionaryWithDictionary:
。只需使用
NSDictionary* dicOpera = [[[NSDictionary dictionaryWithContentsOfFile:pathOpere]
objectForKey:nomeCompositore]
objectForKey:nomeOpera];