为啥解散presentingViewController,只解散子控制器?

Posted

技术标签:

【中文标题】为啥解散presentingViewController,只解散子控制器?【英文标题】:Why dismissing the presentingViewController, only dismisses the child controller?为什么解散presentingViewController,只解散子控制器? 【发布时间】:2013-07-19 00:06:32 【问题描述】:

我已经看到了一些与此相关的问题,但没有一个可以帮助我解决此问题。

我有一个 MasterViewController -> AViewController -> BViewController

文档说:

呈现视图控制器负责关闭它呈现的视图控制器。但是,如果您在呈现的视图控制器本身上调用此方法,它会自动将消息转发到呈现的视图控制器。

[self.presentingViewController dismissModalViewControllerAnimated: YES];

从我的 B VC 调用这个方法,应该关闭我的 A 和 B VC。然而,它只会解雇孩子(B VC)。为什么?

- (IBAction)checkButton:(UIButton *)sender 

    NSManagedObjectContext * context = [myAppDelegate managedObjectContext];
    Work * newWork = [NSEntityDescription insertNewObjectForEntityForName:@"Work" inManagedObjectContext:context];
    [newWork setName:_workName];
    [myAppDelegate saveContext];

    NSLog(@"%@", [self.presentingViewController description]);
    [self.presentingViewController dismissModalViewControllerAnimated: YES];


我不知道这是否相关,但 A 和 B 风投是这样介绍的:

    TWWorkNameViewController *controller = (TWWorkNameViewController *)[self.storyboard instantiateViewControllerWithIdentifier:@"WorkName"];
    [self presentViewController:controller animated:YES completion:nil];

【问题讨论】:

不,它应该只关闭 BViewController。如果 A 展示了 B,那么写 [selfdismiss..](在 B 中)和 [self.presentingViewControllerdismiss..](也在 B 中)是相同的。 但是self.presentingViewController不应该是A VC吗?我从 B 获得了 A 的描述,我可以确认该方法是从 B 在 A 中调用的。我在这里缺少什么? 是的 self.presentingViewController 将是 A,并且由于 A 呈现了 B,A 正在解除它呈现的那个,即 B。当你在呈现的控制器中说 [self dismiss...] 时(B ),该消息被发送到控制器 A,它执行 [self dismiss...],但现在 self 是 A,因为它被转发了。 现在已修复。谢谢好心的先生,您非常清楚的解释并帮助我理解了这一点。 =) 【参考方案1】:

这是因为您的 MasterViewController 正在呈现 AViewController 而这是呈现 BViewController 所以当您使用 [self.presentingViewController dismissModalViewControllerAnimated: YES];您正在关闭 BViewController,因为这是堆栈顶部的那个,如果您想从 BViewController 返回 MasterViewController,您可以使用 Navigtioncontroller 并使用方法

popToRootViewControllerAnimated: “弹出堆栈上除根视图控制器之外的所有视图控制器并更新显示。” http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html

如果您不想使用导航控制器,则需要使用通知: 在您的 MasterViewcontroller 视图中确实加载了这样做:

- (void)viewDidLoad

[super viewDidLoad];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(dismiss) name:@"BACKTOINDEXNOTE" object:nil];


-(void)dismiss

  [self dismissViewControllerAnimated:YES completion:nil];

BViewController 在你的方法里面说

- (IBAction)checkButton:(UIButton *)sender 
 NSNotification * notification = [NSNotification notificationWithName:@"BACKTOINDEXNOTE" object:nil];
 [[NSNotificationCenter defaultCenter] postNotification:notification];

因此,您将关闭 BViewController 和 AViewController。

【讨论】:

我现在明白了。我喜欢你的解决方案,但如果可以的话,我也会把这个留在这里,[[[self presentingVC] presentingVC] dismis...];这沿着堆栈向下(到主 VC)并解散 A 和 B VC。如果有任何理由我不应该这样做。请告诉我。谢谢!【参考方案2】:

按照我的理解,“但是,如果您在呈现的视图控制器本身上调用此方法,它会自动将消息转发到呈现的视图控制器。”指的是呈现的视图控制器本身不呈现任何视图控制器的情况。通常,呈现视图控制器负责关闭它呈现的视图控制器,但如果你在一个没有呈现任何东西的视图控制器上调用dismissModalViewControllerAnimated,则有两个选项 - 要么什么都不做,要么自行关闭它。它通过将该消息转发到其呈现的视图控制器来消除自己是有道理的。如果您在呈现另一个视图控制器的视图控制器上调用 dismissModalViewControllerAnimated,那么它应该关闭该视图控制器,而不是按照文档所述将消息转发给它正在呈现的视图控制器(如果有的话)。

【讨论】:

【参考方案3】:

我不知道这是否是正确的答案,但如果你有 A->B->C 并且你在 C 上并想回到 A,这意味着同时解雇 C 和 B,你可以使用 B 的 presentingViewController。我在 iOS 8 上对此进行了测试。B 和 C 在一个动画中同时关闭。

[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];

【讨论】:

以上是关于为啥解散presentingViewController,只解散子控制器?的主要内容,如果未能解决你的问题,请参考以下文章

轻松实现部分背景半透明的呈现效果

将值从presentingViewController 传回presentingViewController

presentingViewController 是不是与presentingViewController 一起旋转

错误的“presentingViewController”

presentingViewController 总是得到 UITabBarController

presentingViewController 显示为 null