2010-02-12 73 views
5

最近有人在堆栈溢出告诉我下面的代码不漏,该财产处理保留本身:iPhone:这是一个泄漏或不

self.locationManager = [[CLLocationManager alloc] init]; 

中的dealloc:

self.locationManager = nil; 

在.h文件中:

@property (nonatomic, retain) CLLocationManager *locationManager; 

我认为这是一个明显的泄漏,并认为这应该可以修复泄漏:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

但他声称不会工作,因为用他的话说:“你不会自动释放一个类的属性。一个属性的自动生成的访问定义为保留会自动处理保持”

,他让我怀疑他是错的还是我不明白,在所有的内存管理

编辑1:是的代码

self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"]; 

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

内存管理明智的有什么不同?

这家伙说第一个是正确的,拒绝第二个。为什么第二个是错误的?据我可以看到,两个分配autoreleased实例的一些属性,但不知何故仍然存在一个固执的论点,第二个是错误的。我看不到它,任何帮助都会如此受欢迎。

+1

在你的编辑1上,保留智慧,他们是一样的。这些对象都只保留一次。所有便利功能都有一个隐含的自动释放功能。如果你在init语句中没有看到alloc这个词,那么这个变量是自动释放的。如果你使用alloc,你应该使用autorelease – 2010-02-12 23:23:56

回答

7

计数保留和释放有助于在这种情况下。这绝对是一个漏洞。你的locationManager对象将被保留2次:一次由alloc/init调用,一次由属性。将该属性设置为nil将只发布一次locationManager

对于编辑1中给出的例子,它们确实是相同的。这听起来像其他开发人员有一种立即autoreleasing厌恶或不完全明白什么autorelease做。

0

在下面添加下面这行......它显然会给你locationManager的保留计数。这会告诉你是否需要手动释放它。

NSLog(@"retainCount:%d", [locationManager retainCount]); 

编辑:

[locationManager release]; 
+0

不,不,我在概念上问。另外,NSlogging retainCounts不是一个很好的泄漏措施。 – 2010-02-12 15:33:01

+0

哦,好的。那么最好的做法是你应该在dealloc中这样做,因为当autorelease池被耗尽时你的对象不会被释放。上面编辑。 – Zinc 2010-02-12 15:39:29

+0

从NSObject类的引用:“重要提示:在调试内存管理问题时,此方法[retainCount]通常没有任何价值[...],您很难从该方法获得有用的信息。“ – jnic 2010-02-12 15:44:20

1

@jnic:你是惊人的错误。 据我了解,该属性的前一个值将发送释放消息,而不是要分配给该属性的对象。 所以,是的,建议的代码确实泄漏,你必须发送一个autorelease消息,就像你想的一样,ahmet emrah

4

的语义保留属性选项有:

  • 旧值(如果有的话)得到了释放消息
  • 新的价值得到了保留消息

因此,在setter之后,CLLocationManager实例的保留计数为2。一个从分配和一个从保留二传手。你应该二传手后立即发送释放消息:

CLLocationMamnager *aLocationManager = [[CLLocationManager alloc] init]; 
self.locationManager = aLocationManager; 
[aLocationManager release]; 

或者,将其添加到自动释放池中,以便将至少被最终free'd。就像你自己写:

self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 

更妙的是,不要使用保留属性选项。将其保留为,并将其指定为(默认值),并且由于您仍在使用保留的对象,因此您将被设置为去。

+0

非常感谢 – 2010-02-12 19:06:43

-2

好的,这是交易。

当你定义像这样的属性...

@property (nonAtomic, retain) NSString myName; 

...因为属性的默认命令自己居然喜欢将其定义为:

@property (nonAtomic, readwrite, retain, getter=getMyName,setter=setMyName) NSString myName; 

当您使用@synthesize myName;在幕后,编译器生成一个看起来像这样的吸气方法:

-(void) setMyName:(NSString *) aString{ 
    if (!(myString==aString) { //test if a string is the same **object** as the current myString 
     if (aString != nil) { // if nil we don't want to send a retain 
      [aString retain]; // increment the retain count by one 
     }   
     [myString release]; //decrement the retain count of the currently assigned string by one. 
     myString=nil; //set the pointer to nil to ensure we don't point to the old string object 
     myString=aString; //assign the newly retained object to the myString symbol  
    } 
} 

正如您所看到的,来自任何来源的任何字符串,任何之前的保留计数,自动释放或不会自动保留,将在分配时自动保留该方法,并且在分配新值时,该方法将自动释放该值。多个分配不会堆积保留计数。只要您使用生成的setter,分配的对象(在本例中为aString)将始终有一个保留计数,以保持它在类中保持活动状态。

这就是为什么你可以做到这一点...

self.myName=[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"];

不必这样做:

self.myName=[[NSSting stringWithFormat:@"%@ is correct.", @"TechZen"] retain]; 

...而不是担心,如果该字符串值会突然消失autoreleasepool水渠时。

但是如果你打电话......

[self.myName release]; 

... dealloc以外的任何地方,然后在属性的对象我可以,除非你坚持不懈地跟踪它nilled。同样的道理,如果你打电话给..

[self.myName retain]; 

... ...任何地方,然后在属性的对象会泄漏(自对象已释放甚至可能后)。

这就是为什么我说永远保留或自动释放分配的任何物体或复制到一个属性中。这不仅没有意义,而且反作用。因此,当您完成自我对象时,您只想调用发布版本,因为setter对保留计数的有效跟踪意味着即使您仍然需要,您也可以删除该属性。

属性永远不需要自动释放,因为该属性总是由自身对象保留,并且任何其他对象在使用自身对象的属性时都应该在内部处理保留。

一旦您了解生成的访问器内部发生了什么,规则就很明显。永远不要明确保留属性的对象。切勿释放保存在dealloc中的属性对象。切勿自动释放属性的对象。

这些规则的明显必然结果是始终在self对象的内部使用self.propertyName引用,以确保自动管理属性的保留。

+0

Dude, self.myName = [NSSting stringWithFormat:@”%@ is correct。“,@”TechZen “]; 与 完全相同self.locationManager = [[[CLLocationManager alloc] init] autorelease]; memory management-wise。 我不敢相信你怎么看不到它。 – 2010-02-12 18:54:53

2

下面的语句被保留的两倍,因此必须被释放了两次:

self.locationManager = [[CLLocationManager alloc] init]; 

这可能是最好的写法如下:

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 

现在,这个变量一直保留只有一次,并且你可以在你的类的dealloc函数中释放它。

此外,如果您运行下面的代码行,释放被称为:

locationManager = nil; 

由于的LocationManager合成,当你把它设置为nil,它就会被首次发布。

此外,如果你做了以下的LocationManager将首先被释放,然后重置幕后:

self.locationManager = foo; 

最后,下面将与EXC_BAD_ACCESS崩溃,因为你是一个双重释放的LocationManager当你设置到foo:拇指

self.locationManager = [[[CLLocationManager alloc] init]autorelease]; 
[locationManager release]; 
self.locationManager = foo; 
1

规则很简单:如果一个属性被标记为“保留”,总是给它的自动释放的变量(如果要创建它)当然,除非你还需要在其他地方保留。