【问题标题】:Does UIViewController's presentModalViewController:animated: retain the modal controller?UIViewController 的 presentModalViewController:animated: 是否保留模态控制器?
【发布时间】:2011-05-27 12:17:33
【问题描述】:

这会影响我与模态控制器的交互方式。当我第一次开始 iOS 开发时,我认为 UIViewController 没有保留模态呈现的视图。好吧,实际上这更像是我没有理由假设它确实保留了它们。当我知道他们会完成他们的解雇动画时,这让我在释放他们时尝试着相当尴尬:

_myViewController = [[UIViewController alloc] init];
[self. present modalViewController:_myViewController animated:YES];
/* 
Some stuff, then in a different method all together,
probably as the result of a delegate callback or something...
*/
[self dismissModalViewControllerAnimiated:YES];
[_myViewController performSelector:@selector(release) withObject:nil afterDelay:0.5f];

然后,我看到UIViewControllermodalViewController 属性并想,“伙计,我希望它在显示模态视图控制器时保留该属性。”果然,我记录了其中几次尝试的保留计数,并注意到在调用 presentModalViewController:animated: 后立即普遍增加(我知道,保留计数不是一个完美的指标)。所以,在某个地方,我已经开始使用一个更好的模式,我假设我以模态方式呈现的任何控制器对象都由呈现控制器保留。这让我可以编写标准的当前代码:

UIViewController* myViewController = [[UIViewController alloc] init];
[self presentModalViewController:myViewController animated:YES];
[myViewController release]; // <- Fire and forget!

现在,当然,没有尴尬:无需等待动画完成,甚至在不需要时保留对呈现控制器的引用。我可以稍后盲目地关闭它,而不用担心泄漏。我喜欢。

我在模态呈现的控制器中记录了许多 dealloc,它们总是在我想要的时候准确地被调用,这让我对我的方法充满信心:UIViewControllerpresentModalViewController:animated: 将呈现的控制器保留为 @987654329 @属性。

但是,这就是这个问题的实质,我意识到我无法确认这是记录的行为。如果它没有被记录在案,我不应该像我一样感到安全,因为苹果没有承诺无证行为的寿命。 modalViewController 属性是公开的 readonly,所以我只能假设在幕后保留,presentModalViewController:animated: 上的文档只说:

将 modalViewController 属性设置为指定的视图控制器。

“集合”可以是assignretain。我读到的任何东西都没有公然证实或否认我的立场。由于这是我经常做的一个假设,如果有人能指出我在文档中遗漏的某个地方,让我对这种做法的合法性放心,​​我会非常高兴。

编辑:在 iOS SDK 日常生活的起起落落中,我发现自己在 UIViewController 的标题中并开始阅读其中的一些内容。我收集了一些有用的信息,让我想起了这个问题,我决定发布它,以防将来的一些用户偶然发现这个问题并想要尽可能多的信息来满足他们对非常标准做法的偏执。一点点就是这样,来自 UIViewController.h 中的 @interface ivar 块:

UIViewController *_childModalViewController;

与其他声明相反:

UIViewController *_parentViewController; // Nonretained
NSHashTable      *_childViewControllers; // Nonretained

cmets 似乎明确说明了保留的内容。由于缺少对模态视图控制器 ivar 声明的注释,它似乎 被保留了。

【问题讨论】:

  • 这里有同样的问题。有人可以帮忙吗?

标签: iphone objective-c ipad uiviewcontroller


【解决方案1】:

Objective-C 的内存管理规则定义了行为,因此不需要明确记录它保留了模态视图控制器。如果一个对象需要在方法执行完成后保留传递的对象,它保留该对象除非另有说明

所以在这种情况下,您应该将视图控制器传递给presentModalViewController:animated:,然后释放它(或使用自动释放)。

这适用于 Objective-C 的任何地方。如果一个对象将另一个对象作为方法输入,您永远不必代表它保留该对象。

根据 cmets 的要求,如果您阅读 Apple 的 documentation on memory management,那么您会发现 section on Weak References,其中指出:

重要:在 Cocoa 中,引用 表数据源,大纲视图 项目、通知观察者和 代表都被认为是弱的(对于 例如,一个 NSTableView 对象 不保留其数据源和 NSApplication 对象不保留 它的代表)。文档仅 描述了例外情况 约定。

这实际上表明这本身就是一个约定,并且将在文档中说明例外情况,但是,转到NSTableView 的文档并查看setDataSource: 方法,我们看到:

讨论在托管内存中 环境中,接收器保持一个 对数据源的弱引用 (即不保留数据 来源,请参阅与 对象)。设置数据后 源,此方法调用 tile。

这个方法引发了一个 NSInternalInconsistencyException 如果 anObject 也不响应 numberOfRowsInTableView:或 tableView:objectValueForTableColumn:row:。

【讨论】:

  • 委托/弱引用存储方法怎么样?它们将对象作为方法输入,保留它们,而您确实必须代表它保留对象。如果你能告诉我,在文档中的哪个位置,它声明所有弱 ref 存储方法都会明确声明缺少保留,那么我会很高兴。
  • 您的第一个引用似乎设置了一组特定的实例,其中弱引用是默认的,强引用将被记录为例外。它并没有告诉我强引用是默认的,弱引用将被记录为异常,这似乎是您的声明所暗示的:“如果对象需要在方法之后保留传递的对象执行完毕,除非另有说明,否则将保留该对象。"
  • 另外,我意识到我在这里非常挑剔。我很欣赏你的想法,我同意你的观点,就惯例而言,这确实是完全有道理的。
【解决方案2】:

嗯,好问题!我不完全确定你的假设。有问题的属性在文档中定义为:

@property(nonatomic, readonly) UIViewController *modalViewController

正如您所指出的,它没有指定它的存储方式。

本文档: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html

事实上,如果没有指定保留/分配/复制,则分配是默认行为。


我也阅读了 d11wtq 的回复,但不确定我是否完全同意。我同意关于 obj-c 内存管理的约定,但是在很多情况下框架方法不保留属性(想想弱引用、委托等)。我希望有人能证实你的假设。

【讨论】:

  • 我同意你关于弱参考点的观点。我可以看到这在理论上是双向的,这就是为什么我会在坚定的判决下睡得更好。
  • 如果一个对象没有保留一个对象,但需要它留下来,那么该行为应该被记录下来。显然,对于第三方框架,我不能保证这一点,因为这取决于框架的开发人员来记录它,但在苹果产品的范围内,应该记录 100% 规则的例外情况。
  • 您链接到的那个文档是在谈论声明的属性,与这个问题无关。用户询问presentModalViewController:animated:。那只是一种方法...不是声明的属性(顺便说一句,以防万一您认为是我投了反对票,那不是;))属性上的保留/分配内容仅适用于设置器。它对只读属性没有任何作用。
【解决方案3】:

确保它已记录在案。顺便说一句,我不知道其他方式:D 我从 1.5 年前开始 iOS 编程开始就使用 alloc-present-release 方法

如果您启动 XCode 并创建“实用程序应用程序”,您可以找到示例代码。 在(Apple 提供的)代码中应该是:

FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:@"FlipsideView" bundle:nil];
controller.delegate = self;

controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];

[controller release];

【讨论】:

    【解决方案4】:

    我猜 iPortable 的回答给了你你想要的——当你以这种方式释放视图控制器时,你的内心是平静的。

    顺便说一句,打印出 retainCount 不是一个好的调试策略的部分原因是因为你放置 NSLog 或断点的位置可能不是查看保留计数的正确位置。在您检查由您感兴趣的事件引起的保留计数之后,可能会出现一些保留或释放。

    因此,如果您真的想知道事件发生后的保留计数是多少,只需覆盖 -(id) release 和 -(void) release 方法并在那里打印日志,然后自己计算。当然,您必须在方法结束时调用超类的保留/释放。例如,通过这种方式,您可以获得对原始问题的非常明确的答案。

    【讨论】:

      【解决方案5】:

      如果你正在做一个动画,同时呈现模态视图控制器,比如

      [viewController presentViewController:modalViewController animated:YES completion:^{
          NSLog(@"presentViewController completion");
      }];
      /*DONT RELEASE IF THERE IS ANIMATION*/
      //[modalViewController release];
      

      释放对象不是一个好主意。而是将调用回调到可以释放该类的调用类。

      如果您不使用动画,那么您可以在模态显示后立即释放它,如下所示。

         [viewController presentViewController:modalViewController animated:NO completion:^{
          NSLog(@"presentViewController completion");
      }];
      
      [modalViewController release];/*YOU MAY RELEASE MODALVIEW CONTROLLER IMMEDIATELY*/
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-21
        • 2011-03-12
        相关资源
        最近更新 更多