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

Iphone 目标c,实例成员的内存管理,iphone,objective-c,ios,memory-management,Iphone,Objective C,Ios,Memory Management,我被实例成员的内存管理弄糊涂了。我有一门ivar课程: DetailedResultsTableViewController *detailedResultsTableViewController; 及 在.m文件中: @synthesize detailedResultsTableViewController; 及 当我初始化此变量时: self.detailedResultsMapViewController = [[DetailedResultsMapViewController al

我被实例成员的内存管理弄糊涂了。我有一门ivar课程:

DetailedResultsTableViewController *detailedResultsTableViewController;

在.m文件中:

@synthesize detailedResultsTableViewController;

当我初始化此变量时:

self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
我在初始化之后测试了重新计数,结果是2!!!如果我在函数结束时释放它,它将属于未分配对象。我做错了什么?我应该如何初始化这种类型的变量?
谢谢

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

值得注意的是,我不太相信重新计算,它有时会给出错误的结果,不过这次是正确的

以下是一些避免保留计数为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

有两种方法

  • 您可以在init alloc语句中包含自动释放
  • 在设置实例时创建一个临时变量,然后在设置完属性后释放临时变量
  • 放下自我。为了这次任务。这里的问题是,如果您有一个自定义的setMyVariable:函数,那么在没有self的情况下将不会调用它
  • 使用ARC,您不必担心这些
    你做错了两件事

    首先:

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

    self.detailedResultsMapViewController = [[[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil] autorelease];
    
    因为您使用的是
    self….
    属性的内存管理语义,在本例中是
    retain
    ,所以它会再次被保留

    其次:

    self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
    
    您使用了
    retainCount
    。它在调试内存管理时没有任何用处

    如果你想知道为什么这是错误的,看看其他关于堆栈溢出的关于重新计数的答案,或者阅读@bbum关于为什么不应该使用它的内容


    你违反了内存管理规则,没有释放你拥有的东西。仅此一点就足以在代码中发现问题。事实上,我很惊讶静态分析仪没有发现这个问题。

    首先,您不应该查看重新计数,它不太可靠

    其次,您的属性设置为保留。因此,当您为其分配某些内容时,它将增加reatincount。与alloc一样
    alloc

    这样做会让你泄密:

    self.detailedResultsMapViewController = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
    
    你应该做:

    DetailedResultsMapViewController *vc = [[DetailedResultsMapViewController alloc] initWithNibName:@"DetailedResultsMapViewController" bundle:nil];
    self.detailedResultsMapViewController =vc;
    [vc release], vc= nil;
    
    或使用自动释放:

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

    您的
    @接口
    是正确的,但您的实现稍有错误:

    @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];   
    

    设置方法的代码不“拥有”新值,因此它必须使用属性和合成为您提供一个新方法。在本例中,您将为
    detailedResultsTableViewController
    提供一个新的set和get方法。这是在编译时为您生成的(即没有需要添加的代码)

    此集合方法将是

    - (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,它也将执行retain

    如果您使用的是属性,那么您将使用

    DetailedResultsTableViewController *d = [[DetailedResultsMapViewController alloc] init...]
    self.detailedResultsMapViewController = d;
    [d release];
    
    这样做的好处是,您不必记住在分配新对象之前释放旧对象,因为合成方法会为您这样做。你也可以这样做

    self.detailedResultsMapViewController = nil;
    
    在您的dealloc方法中,如果您已经在其他地方发布了它,您就不必担心了


    了解这一点很有用,因为您可以通过手动输入代码来覆盖set方法,该代码允许您在设置对象时执行操作。

    非常感谢!!!这就是我要找的!为什么我应该使用
    vc=nil?它是强制性的吗?不,它更像是一种惯例。在应用程序不崩溃的情况下,调用
    nil
    对象上的方法。关于尼林的一些有趣的阅读:这只是一件“好事”。它可以防止问题,如果你继续发送消息到vc进一步你的代码,但你只是有东西不工作,而不是崩溃的应用程序。请参阅我的答案,了解背景中正在发生的事情的详细信息,这可能有助于您更好地理解属性。问题:如果使用ARC怎么办?那么您的第一个代码段可以接受吗?因为自动释放是不允许的?哎呀,我被转移到那里了。。。如果使用了ARC,那么您的第二个代码段是否正确。因为ARC下允许自动释放?顺便说一句,我还是喜欢你的下一个到最后一个分段的方式。这不是真正的自动发布。这是为了解释当您在代码中使用
    @property
    @synthesis
    时编译器“幕后”会发生什么。我认为,这在很大程度上有助于理解代码中过度保留或过度发布的潜在问题。我见过很多人不了解正在发生的事情,他们或者发现很难理解何时使用retain,何时不使用properties。
    self.detailedResultsMapViewController = nil;