1

只是为了学习 xCode 的某些特定方面,我正在创建一个具有 2 个功能视图控制器的简单应用程序。每个都包含一个按钮,可以按下该按钮切换到另一个。我没有使用segues。我正在使用从应用程序委托中检索到的指针。

视觉插图(点击以获得更高的分辨率): 视觉的

当应用程序加载时,根视图控制器呈现视图 1。当您单击“切换到视图 2”时,以下代码会导致视图 2 出现:

- (IBAction)buttonPressed:(id)sender
{
    AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    [self presentViewController:appDelegate.view2 animated:YES completion:nil];
}

到目前为止,一切都很好。

但是,当您在第二个视图上单击“切换到视图 1”时,同样的代码(将“view2”替换为“view1”)会出现以下错误:

应用程序试图以模态方式呈现活动控制器。

总结一下(其中 --> = 表示),我们有 root --> view1 --> view2 -x-> view1

我不在乎保留谁呈现谁的历史。我只是想让按钮将之前显示的视图控制器带到顶部(使其可见),保持其视图的状态。

很高兴知道以下内容:

  1. 是否有一种解决方法可以让我使用 presentViewController 实现预期的行为?例如,根 --> view2 --> view1

  2. 对于实现所需行为,还有哪些其他方法更实用?它/他们必须使用应用程序委托,因为在我的实际应用程序中这是不可避免的。

  3. 我是否通过尝试将视图控制器放在顶部而不集成到更大的架构中来打破规则?例如,这种行为是否应该由导航控制器和推送/弹出来处理?如果是这样,你能解释为什么 xCode 不希望我这样做吗?为什么我不能只显示我想要的任何视图控制器,而不一定与其他视图控制器有任何关系?(也许是因为这可能导致滥用应用程序委托?)

  4. “呈现”视图控制器的真正含义是什么?除了在演示者和演示者之间创建指针之外,它还需要哪些功能限制或功能?让呈现视图控制器“活动”有什么重要性?

  5. 如果改为让 view1 上的按钮将presentViewController消息发送到根视图(我希望只是将表示链从 root --> view1 更改为 root --> view2,让 view1 仍然存在于内存中,但不是该链的一部分) ,我得到一个不同的错误:“尝试呈现其视图不在窗口层次结构中!” 这是什么意思?我找不到窗口层次结构的解释。

好的,我知道我在这里问了很多,但是任何启发都将不胜感激!

4

2 回答 2

3

执行此操作的正确方法是让底层 rootVC 进行呈现和解散(正如您在第 5 点中尝试的那样 - 没有解散部分)。当您想要展示另一个时,您可以通过从 view1 和 view2 中的每个向 rootVC 发送消息 + 完成块来实现这一点。

当您在 view1 中时:

- (IBAction)buttonPressed:(id)sender 
    AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];

    UIViewController* presentingVC = self.presentingViewController;
    [presentingVC dismissViewControllerAnimated:YES completion:^{
          [presentingVC presentViewController:appDelegate.view2 
                                     animated:YES 
                                   completion:nil];
    }];
}

对于 view2 也是如此。注意你需要这条线:

        UIViewController* presentingVC = self.presentingViewController;

因为您不能在完成块内引用“self.presentingViewController”,因为此时它的控制器已被解除。

我认为这回答了第 1 点和第 2 点。

回答第 3 点“为什么我不能只显示我想要的任何视图控制器,而它不一定与其他视图控制器有任何关系?” - 你可以(通过rootViewController窗口的属性),但是将不得不实现导航和管理你的 viewController 指针,这意味着你最终将创建某种控制器。Apple 通过为您提供一些满足大多数需求的产品来帮助您。

关于您的第 4 点 - viewController 的呈现由呈现的 VC 控制,这就是为什么您要保持该 VC 的“活动”。当您发送此消息时: [self dismissViewControllerAnimated:completion:]self只需将消息重新路由到它的presentingViewController. 如果你摆脱你presentingViewController的解雇方法将打破。

第 5 点已在上面回答。在要求显示底层视图之前,您需要先关闭最顶层的视图。请注意, view1 “仍在内存中”,但这只是因为您在应用程序委托中保留了指向它的指针。

更新

当你试图让它与初始的launch-straight-to-view1一起工作时,你可以创建一个 BOOLlaunched属性并从你的 rootViewController 中检查/设置它viewDidAppear

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    if (!self.launched) {
        self.launched = TRUE;
        AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
        [self presentViewController:appDelegate.view1
                           animated:YES
                         completion:nil];
    }
}
于 2013-05-13T01:37:44.377 回答
1

让我试着一一解决你的观点。

1) 不,你不应该用 presentViewController 来做这一切。

2)如果你想做root --> view1 --> view2 --> view1,那么你不要用presentViewController来做这一切。要从 view1 回到 view2,你应该使用dismissViewControllerAnimated:completion。

3) 当你使用 presentViewController:animated: 时,视图控制器确实有关系。呈现控制器有一个指向它呈现的控制器的指针,而呈现的控制器有一个指向呈现它的控制器的指针。所以,无论你是否愿意,你都会得到这些关系。有一种方法可以显示您想要的任何控制器,它们之间没有任何关系——只需重置窗口的根视图控制器。旧的视图控制器将被释放(如果您不保留指向它的强指针),新的视图控制器将成为窗口的根视图控制器。

4) 呈现视图控制器使该控制器成为模态视图控制器——它接管了整个屏幕,旨在用作应用程序流程的中断。你真的不应该广泛使用它们来从一个控制器转到另一个控制器(尤其是不要“倒退”到以前的控制器)。由于它应该被使用的方式,你通常想回到呈现它的控制器,所以这就是它保持“活动”的原因(在它没有被释放的意义上)。

5) 你得到那个错误是因为 root 的视图不在屏幕上,而 view1 的在屏幕上。您需要在屏幕上显示来自控制器的视图控制器。

于 2013-05-13T01:18:19.320 回答