UIViewController的presentModalViewController:animated:保留模态控制器吗?

时间:2010-12-18 08:28:04

标签: iphone objective-c ipad uiviewcontroller

这对我与模态控制器的交互方式有影响。当我第一次开始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];

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

presentModalViewController:animated:

现在,当然,没有尴尬:不需要等待动画完成,或者如果我不需要它,甚至可以保持对所呈现的控制器的引用。我可以稍后盲目解雇,不要担心漏水。我喜欢它。

我在我的模态控制器中记录了很多dealloc,它们总是在我想要时准确调用,这让我对我的方法充满信心:UIViewController* myViewController = [[UIViewController alloc] init]; [self presentModalViewController:myViewController animated:YES]; [myViewController release]; // <- Fire and forget! 的{​​{1}}保留了所呈现的控制器作为UIViewController属性。

但是,这就是这个问题的核心,我意识到我无法确认这是 记录的 行为。如果没有记录,我不应该感觉像我一样安全,因为Apple没有对未记载行为的长寿做出任何承诺。 presentModalViewController:animated:属性是公开modalViewController,因此我只能假设在幕后保留,而modalViewController上的文档只说:

  

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

“集合”可以是readonlypresentModalViewController:animated:。我没有看到任何公然确认或否认我的立场。由于这是我经常做的一个假设,如果有人能够指出我错过文档内容的某个事实让我对这种做法的合法性感到放松,我真的很喜欢它。

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

assign

与其他声明相反:

retain

评论似乎明确说明保留的内容。由于缺乏对模态视图控制器ivar声明的评论,它似乎 保留。

5 个答案:

答案 0 :(得分:14)

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

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

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

根据评论中的要求,如果您阅读了Apple的documentation on memory management,那么您会找到section on Weak References,其中说明:

  

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

这实际上表明这本身就是一个约定,并且文档中会说明异常,但是,转到NSTableView的文档并查看setDataSource:方法,我们看到:< / p>

  

讨论在托管内存中   环境,接收器维护一个   弱引用数据源   (也就是说,它不会保留数据   来源,见沟通   对象)。设置数据后   source,此方法调用tile。

     

这种方法提出了一个   NSInternalInconsistencyException如果   anObject也没有响应   numberOfRowsInTableView:或   的tableView:objectValueForTableColumn:行:

答案 1 :(得分:2)

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

@property(nonatomic, readonly) UIViewController *modalViewController

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

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

实际上,声明如果未指定retain / assign / copy,则该assign是默认行为。


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

答案 2 :(得分:2)

确保记录在案。顺便说一下,我不知道另一种方式: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];

答案 3 :(得分:1)

我想iPortable的回答可以为您提供所需的内容 - 当您以这种方式释放视图控制器时,您的心中会感到平静。

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

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

答案 4 :(得分:0)

如果您在呈现模式视图控制器(如

)时正在执行动画
[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*/