我有一个内存泄漏问题,我无法理解!观看这个初始化方法:
- (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;}
第一个变体会产生内存泄漏,第二个则不会!我就是不明白为什么! Instruments 证明了内存泄漏,突出显示了这一行:
[NSDictionary dictionaryWithContentsOfFile:pathOpere]
这是dealloc方法:
- (void)dealloc {
[tipologia release];
[compositore release];
[nomeCompleto release];
[super dealloc];}
最佳答案
请记住alloc
返回您拥有的对象。
如果您将三个字符串属性声明为 retain
,将这些对象分配给您的属性意味着您现在拥有每个对象两次 - 一次是因为您分配了它,另一次是因为您将它分配给了您的属性。这些对象仍然存在,因为没有任何东西释放它们的第二所有权。
如果您将属性声明为 copy
(这是声明 NSString 属性的正确方法),分配对象并将副本存储为属性的值。您无需对原始对象进行任何进一步操作,这些对象仍然存在,因为没有任何东西释放它们。
无论哪种方式,这都是你的泄漏。
该属性应声明为 copy
;如果已经存在,请不要尝试通过更改来修复泄漏。
您不应在此处使用属性访问。请记住,分配给属性是 set<PropertyName>:
消息,并且您的对象尚未完全初始化。向未完全初始化或未完全释放的对象发送消息会带来麻烦,特别是在涉及子类时,因为它们可能会以父类(super class)不希望的方式重写访问器方法。
所以,在 init
只是,直接分配给实例变量。在 dealloc
仅限,发送release
消息直接发送到实例变量中的对象。在其他地方,请使用属性访问。
您也不应该使用alloc
和initWithString:
这里。它会起作用,但惯例是发送 copy
向您已有的对象发送消息,与属性相同。发送copy
消息到您的输入字符串对象,然后将副本分配给您的实例变量。
当您确实使用属性访问时,请使用便捷构造函数(例如 stringWith…:
),因为这些返回的对象不属于您。当您将这些对象分配给您的copy
时-声明的属性,您实际上将存储您拥有的副本。
另一种方法是使用 alloc
和initWithWhatever:
,然后立即autorelease
在将该对象分配给属性之前;这种方式会创建一个您拥有的对象,然后立即放弃所有权,然后再将其分配给属性。
关于objective-c - plist 文件加载的 NSDictionary 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2887736/