从UINavigationController堆栈中移除控制器

3

我不明白为什么在这种情况下FirsViewController没有被销毁/释放。

我的AppDelegate.m - FirstViewController被推入堆栈中。

self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
self.navigationController = [[UINavigationController alloc]init];

self.FirstViewController = [[FirstViewController alloc]
                                         initWithNibName:@"FirstViewController" 
                                         bundle:[NSBundle mainBundle]];
[self.navigationController FirstViewController animated:YES];

FirstViewController.m

 self.SecondViewController = [[SecondViewController alloc]
                                             initWithNibName:@"SecondViewController" 
                                             bundle:[NSBundle mainBundle]];
    self.SecondViewController.totalNumberOfPlayers = self.selectedRow;
    [self.navigationController pushFadeViewController:self.SecondViewController];
    [self.view removeFromSuperview];

-(void)dealloc
{
  [SecondViewController release];
  NSLog(@"SecondViewController released");
}

当我运行应用程序并从第一个视图控制器切换到第二个视图控制器时,控制台中没有NSLog输入。这使我认为第一个视图控制器没有被销毁,它的内存也没有释放。

似乎[self.view removeFromSuperview]在这种情况下不能正常工作。

我的问题是如何释放/销毁FirstController? 在应用程序的其余部分中将永远不会使用它。

1个回答

16
你说的没错,视图控制器在栈中不会被释放或销毁。这不是一个错误——这是有意为之的,因为如果你弹出当前的视图控制器,它需要再次显示底层的视图控制器。应用程序并不知道你永远不打算这样做。
[self.view removeFromSuperview]不能起作用,因为它从窗口中移除了视图(当你推送第二个视图控制器时,窗口已经被移除了),而不是从堆栈中移除视图控制器(我想你可能混淆了视图和视图控制器)。
如果你想摆脱第一个视图控制器,在推送第二个视图控制器时,不要使用:
[navigationController pushViewController:secondViewController animated:YES];

请使用以下代码:

[navigationController setViewControllers:[NSArray arrayWithObject:secondViewController] animated:YES];

这将完全替换第一个视图控制器,而不仅仅是将新的视图控制器推到其顶部。动画效果将相同。

请注意,在调用上述方法后,第一个视图控制器将立即被释放,因此不要尝试在调用此方法后对第一个视图控制器进行任何操作,否则很可能会导致崩溃。

更新:

以下是您的应用程序委托设置代码应该如何看起来:

self.window = [[[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.navigationController = [[[UINavigationController alloc] init] autorelease];

FirstViewController *firstViewController = [[FirstViewController alloc] init];
[self.navigationController pushViewController:firstViewController animated:YES];
[firstViewController release];

需要注意的事项:

  1. 不要将firstViewController存储在属性中,否则在弹出并且dealloc仍然无法被调用时它将不会被释放(可以删除firstViewController属性)。

  2. 变量名使用小写,只有类名大写。

  3. 始终释放或自动释放在创建它们的同一方法中alloc/init的对象 - 这将避免分析器警告(并避免泄漏)。

  4. 如果nib文件名与视图控制器类名匹配,则不需要指定nib文件。

Nick


在完成使用self.FirstViewController属性后,您需要将其设置为nil,否则它不会被释放。您可以使用setViewControllers:方法多次,但是除非使用pushViewController:显示下一个视图,否则无法使用popViewController:方法返回到先前的视图。 - Nick Lockwood
当您创建第一个视图控制器时,应用程序委托中存在泄漏,因为您[[alloc] init]它(保留计数= 1),然后将其分配给保留的属性(再次保留它,保留计数= 2),但您从未释放它。泄漏工具仅在最后一个对象引用被删除时标记泄漏,因此当您将属性设置为nil并将其从视图控制器中删除时,保留计数仍将为1,您将泄漏,但由于您从未将属性设置为nil,因此泄漏实际上从未发生。分析器更可靠,因为它在泄漏发生之前就看到了泄漏。 - Nick Lockwood
再次感谢Nick!为了避免泄漏,我应该在[navigationController setViewControllers:[NSArray arrayWithObject:secondViewController] animated:YES]之后添加[FirstViewController release]。对吗? - Profo
@NickLockwood,设置 Navigation Controller 的 viewControllers 属性对我有一个不幸的影响 - 控制台会输出一个警告:以意料之外的状态完成导航转换。导航栏子视图树可能被破坏。除此之外,它能正常工作。有什么方法可以抑制这个警告吗? - zaitsman
听起来你可能在另一个导航转换期间设置了viewControllers数组(例如,在导航堆栈的动画推送/弹出之后立即执行)。您需要避免在它正在进行动画时操作导航堆栈,否则您将收到此警告。 - Nick Lockwood
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接