【问题标题】:Does UIView's addSubview really retain the view?UIView 的 addSubview 真的保留视图吗?
【发布时间】:2009-06-02 03:09:18
【问题描述】:

我遇到的情况似乎并非如此。在下面的代码 sn-p 中,如果我删除该行:self.navigationController = nav,根控制器的视图将不会显示,这向我暗示 addSubview 可能实际上不会像其他建议的那样保留视图。有什么想法吗?

- (void)applicationDidFinishLaunching:(UIApplication *)application {   
   self.testViewController = [[TestViewController alloc] initWithNibName:@"TestView" bundle:  [NSBundle mainBundle]];

   UINavigationController *nav = [[UINavigationController alloc]  initWithRootViewController:self.testViewController];

   self.navigationController = nav;  //<-- if this line is removed, test view won't show up

   [window addSubview:nav.view];

   [nav release];
}

【问题讨论】:

  • 您标记的答案不正确,原因我在下面评论。

标签: iphone cocoa-touch uikit


【解决方案1】:

这一行:

[window addSubview:nav.view];

不会立即向屏幕添加视图。它由操作系统在可能不同的线程上的某个未来运行循环中显示。我们无法确定的实际实现。

这就是 Apple 定义像 viewDidAppear/viewWillAppear 这样的委托方法的原因,否则我们将不需要它们,因为我们可以准确地知道这些事件何时发生。

此外,如您所说,添加子视图确实保留了视图。它确实但保留了视图控制器或导航控制器。由于导航控制器保留任何添加的视图控制器,我们不必用 ivar 支持它们。

但是,您对导航控制器的引用必须持续超出该方法的范围。或者根据您的代码,它可能会被解除分配或丢失其引用。

因此,您必须使用 ivar 保留对导航控制器的引用并将其设置为:

self.navigationController = nav; 

因此,即使 nav.view 包含一个指向 testViewController.view 的指针,应用程序也没有引用导航控制器,进而也没有引用视图。结果是一个空白屏幕。


为了更清楚地表明这不是保留/释放问题,您实际上是在以下方法中泄漏:

self.testViewController = [[TestViewController alloc] initWithNibName:@"TestView" bundle: [NSBundle mainBundle]];

您需要通过以下方式自动释放以平衡您的保留/释放:

self.testViewController = [[[TestViewController alloc] initWithNibName:@"TestView" bundle: [NSBundle mainBundle]] autorelease];

因此,这意味着在您运行此代码时,您的视图从未被释放过。这进一步向我们保证,您的问题确实是一个丢失的参考。

【讨论】:

  • view 在窗口保留之前就被释放是不正确的。如果是这种情况,当窗口尝试访问已释放的对象时,您会看到一个异常。真正被释放的是导航控制器,它阻止它使用有趣的内容(如导航栏和根视图)填充其视图。
  • 经过深思熟虑后,我添加了一些附加信息,这也有助于解释您所看到的。
  • 谢谢,我说错了我的意思是导航控制器,我会更新。
  • 希望这是一个更好的答案
  • 我想我对你对“视图”的使用感到困惑——我指的是导航控制器的视图(它确实被窗口保留并显示),而你指的是永远不会显示的根控制器的视图(即 testViewController.view)。
【解决方案2】:

问题可能不是视图没有保留,而是控制器没有保留。

没有这一行:

self.navigationController = nav

没有任何东西保留导航控制器。让视图比控制器寿命更长会很奇怪。

【讨论】:

  • 视图不会“神奇地”绑定到视图控制器。一个视图不仅仅因为它的视图控制器死了而死。如果视图已保留在其他地方,它绝对会比任何视图控制器寿命更长。
  • 我没有说它不会发生。我说如果一个人比另一个人活得长,那就太奇怪了。尤其是当视图是导航控制器的视图时,它是导航控制器构建的一些内部视图层次结构。
  • 如果你遵循约定,你是对的。我唯一的观点是,它本身并不是一个原因。这往往是正确的唯一原因是因为您通常不会在从视图层次结构中删除其视图之前释放视图控制器。但是 UIViewController 中没有任何机制可以阻止你这样做,它只是源于正确的内存管理实践。
  • 乔恩的答案是最准确的。虽然 nav.view 被窗口保留,但 nav 本身被释放和释放。因此,导航控制器永远不会在其视图中放置任何有趣的东西(例如显示根视图控制器)。
  • 很久以前,但是导航没有被释放和释放。它实际上已发布。但是,对 nav 的引用在该方法的范围之外丢失了。这意味着 Cocoa 渲染引擎在未来的运行循环中尝试绘制视图时将有一个无效的指针。
【解决方案3】:

对我来说,这看起来不像是一个保留/释放问题。如果您注释掉 self.navigationController = nav;,您的视图将不会显示,因为在下一行中,[window addSubview:self.navigationController.view] 您的 self.navigationController 属性将不会被设置。它可能是 nil 或者它会崩溃,但如果没有更多代码就无法确定。

【讨论】:

  • 当事情不起作用时,我已经将代码更新回原始代码,我不得不将 self.navigationController 引入到事物中以保存对导航的引用。此外,您在上面看到的是所有代码,仅此而已。
  • 在objective-c中,ivars从0开始。所以,self.navigationController就是nil。
猜你喜欢
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多