Nib 创建的视图保留文件的所有者防止 UIViewController 的释放

Posted

技术标签:

【中文标题】Nib 创建的视图保留文件的所有者防止 UIViewController 的释放【英文标题】:Nib-created view retaining file's owner prevents deallocation of UIViewController 【发布时间】:2011-10-11 23:14:19 【问题描述】:

我有一个想要释放的视图控制器(然后可能稍后在应用程序中重新分配)。问题是它的视图似乎对它有很强的引用,如下面的堆栈跟踪所示。视图是否需要在视图控制器之前被释放?如果是这样,我该怎么做?感谢您的帮助:)

代码:

- (void)setCurrentCourse:(Course *)newCourse

    ... Reference count management ...

    // area of concern
    if (currentCourse == nil) 

        [self.rvc.view removeFromSuperview];
        [self.rvc release];
        // HERE I want rvc to be deallocated, but the retainCount is one.
     else 
        // This is where I allocate the rvc instance
        self.rvc = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle] courseSelectionController:self];
        [self.view addSubview:self.rvc.view];
    

来自覆盖的回溯 -(id)retain;

#0  -[RootViewController retain] (self=0x1bb610, _cmd=0x349b6814) at RootViewController.m:609
#1  0x340b1cdc in CFRetain ()
#2  0x341620c0 in __CFBasicHashStandardRetainValue ()
#3  0x34163440 in __CFBasicHashAddValue ()
#4  0x340b1ff8 in CFBasicHashAddValue ()
#5  0x340b6162 in CFSetAddValue ()
#6  0x340c3012 in -[__NSCFSet addObject:] ()
#7  0x348cb70c in -[UINib instantiateWithOwner:options:] ()
#8  0x348cce08 in -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] ()
#9  0x348465e8 in -[UIViewController _loadViewFromNibNamed:bundle:] ()
#10 0x34813fa4 in -[UIViewController loadView] ()
#11 0x346f8ebe in -[UIViewController view] ()

【问题讨论】:

你能在你使用视图控制器的地方显示代码吗? 【参考方案1】:

假设rvc 是一个保留属性,你有一个泄漏。这就是控制器没有得到deallocated 的原因。当您创建视图控制器时,您会过度保留它:

self.rvc = [[RootViewController alloc] initWithNibName:...];

alloc 返回一个保留对象 (+1)。然后,属性设置器也保留对象 (+2)。稍后,当您释放 (-1) 对象时,您会得到 +1。

要解决此问题,请使用临时变量或autorelease

self.rvc = [[[RootViewController alloc] initWithNibName:...] autorelease];

另一个问题是您释放属性所持有的对象的方式:

[self.rvc release];

在此声明之后,您已经放弃了对象的所有权,并且没有任何东西可以保证该对象在将来仍然有效,但您的属性仍然持有指向它的指针。换句话说,你有一个潜在的悬空参考。所以,当你用这个单一的语句释放它时,将属性 nil (这将释放旧对象):

self.rvc = nil;

【讨论】:

谢谢。那么......我应该重命名我的问题吗? :D 不客气。我认为您不应该重命名您的问题,因为它反映了您最初的想法。【参考方案2】:

[self.rvc release]; 更改为[rvc release];

- (void)setCurrentCourse:(Course *)newCourse 
    // area of concern
    if (currentCourse == nil) 
        [self.rvc.view removeFromSuperview];
        [rvc release];
        // HERE I want rvc to be deallocated, but the retainCount is one.
     else 
        // This is where I allocate the rvc instance
        rvc = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle] courseSelectionController:self];
        [self.view addSubview:self.rvc.view];
    

或使用self.rvc = nil;,因为当您将 nil 设置为实例变量时,setter 只会保留 nil(什么都不做)并释放旧值。

并使用

rvc = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle] courseSelectionController:self];

而不是

self.rvc = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle] courseSelectionController:self];

【讨论】:

感谢您的回答。我的问题仍然存在。 [self.rvc release] 有什么问题? 尝试将self.rvc = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle] courseSelectionController:self];也更改为rvc = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:[NSBundle mainBundle] courseSelectionController:self]; 自我。调用自动生成的设置器代码,该代码保留传递的任何内容,因此分配某些内容,然后将其发送到 self.property 使其保留计数为 2,而不是您想要的 1。有关更详细的解释,请参阅 albertamg 的答案。

以上是关于Nib 创建的视图保留文件的所有者防止 UIViewController 的释放的主要内容,如果未能解决你的问题,请参考以下文章

创建标题 NIB 并在所有视图上显示

尝试使用 .nib 加载视图控制器失败

从 NIB 加载的自定义视图始终旋转 90 度

如何在不使用 Nib 的情况下实例化和调用 UIView 子类

NIB 文件中的静态表格单元格

Nib 文件中包含哪些对象? [复制]