目标c,实例成员的内存pipe理

我对实例成员的内存pipe理感到困惑。 我有一个ivar的课:

DetailedResultsTableViewController *detailedResultsTableViewController; 

 @property (nonatomic, retain) DetailedResultsTableViewController *detailedResultsTableViewController; 

在.m文件中:

 @synthesize detailedResultsTableViewController; 

 [detailedResultsTableViewController release]; 

当我初始化这个variables时:

 self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil]; 

我testing了这个init后的retaincount,它是2! 如果我释放它在函数结束它将落入未分配的对象。 我究竟做错了什么? 我应该如何初始化这种types的variables? 谢谢!!

首先,你不应该看待这个零售商,它不是真的可靠的。

第二你的财产被保留。 所以当你分配一些东西的时候,它会增加重新计算。 如将alloc

像这样做,你泄漏:

 self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil]; 

你应该做:

 DetailedResultsMapViewController *vc = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil]; self.detailedResultsMapViewController =vc; [vc release], vc= nil; 

或者使用Autorelease:

 self.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease]; 

使用属性和综合给你一个新的方法。 在这个例子中,你将有一个新的设置,并为detailedResultsTableViewController获取方法。 这是在编译时为您生成的(即没有必须添加的代码)

这套方法将会是

 - (void)setDetailedResultsTableViewController:(DetailedResultsTableViewController *)c { if (detailedResultsTableViewController != nil) { [detailedResultsTableViewController release]; detailedResultsTableViewController = nil; } detailedResultsTableViewController = [c retain]; } 

所以,当你打电话

 self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] init...]; 

你实际上打电话的是

 [self setDetailedResultsMapViewController:[[DetailedResultsMapViewControler...]]]; 

所以你实际上做了两个保留。 你正在调用alloc … init。 然后另一个,因为你是隐式调用setDetailedResultsMapViewController然后将做一个保留。

如果你正在使用属性,你会使用

 DetailedResultsTableViewController *d = [[DetailedResultsMapViewController alloc] init...] self.detailedResultsMapViewController = d; [d release]; 

这样做的好处是,在分配新的对象之前,您不必记住释放旧对象,因为合成的方法可以为您创build新对象。 你也可以做

 self.detailedResultsMapViewController = nil; 

在你的dealloc方法中,如果你已经在别处释放了它,你将不必担心。

这一点很有用,因为您可以通过手动input代码来覆盖set方法,这样可以在设置对象时执行某些操作。

你做错了件事

首先:

 self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil]; 

应该:

 self.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease]; 

因为你正在使用self.…你正在使用属性的内存pipe理语义,在这种情况下是retain所以它被保留了下来。

其次:

你已经使用了retainCount 。 在debugging内存pipe理方面没有任何用处。

如果你想知道为什么这是错误的看看有关retainCount在Stack Overflow上的其他答案,或者阅读@ bbum 更全面的描述为什么你不应该使用它。

你通过不释放你拥有的东西来打破内存pipe理规则。 这足以在您的代码中find问题。 事实上,我很惊讶静态分析仪没有发现这个问题。

每当你声明一个属性为retain ,并且使用self.myiVar引用它时,它将使用setter,setter将保留该对象。 此外,因为您正在使用对象上的分配,这也会增加保留计数到2,使保留计数为2。

作为一个说明我不会相信retainCount太多,有时会给出不正确的结果,但是这次是正确的。

这里有一些选项可以避免保留计数为2:

 //Refer to it with using the setter detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil]; //Autorelease it after alloc detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease]; 

当你有一个保留的属性,它会增加任何self.myProperty =的保留计数

Alloc也增加保留计数。 所以在你的情况下,保留数是2。

有几个方法。

  1. 你可以在你的init alloc语句中包含autorelease
  2. 创build一个临时variables,而你设置你的实例,然后当你完成设置你的财产,并释放临时工。
  3. 放下自我。 为这个任务。 这里的catch是如果你有一个自定义的setMyVariable:函数,那么它将不会被调用没有自我。
  4. 使用ARC,你不必担心这一点。

你的@interface是正确的,但是你的实现有点不对:

 @implmentation MyClass //It's good practice to explicitly state the a variable name for this property to use //The common approach is to use the property name with a leading underscore //This prevents accidentally accessing the ivar within the class instead of using the accessor methods. You should only access the ivar directly within the accessor methods (which in these case are being created for you by @synthesize), in the designate init method and dealloc @synthesize detailedResultsTableViewController = _detailedResultsTableViewController; -(void)dealloc { //... [_detailedResultsTableViewController release]; //... } @end 

访问该物业时:

 myClass.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease]; 

设置方法的代码不拥有新的值,因此它必须autorelease