为了学习xCode的某些特定方面,我正在创建一个具有2个功能视图控制器的简单应用程序。每个按钮都包含一个按钮,可以按下切换到另一个按钮。我不是在使用segues。我正在使用从app delegate中检索的指针。
当应用程序加载时,根视图控制器显示视图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->厂景
我不关心谁保留谁的历史。我只是希望按钮能够将之前显示的视图控制器置于顶部(使其可见),并保持其视图的状态。
了解以下内容会很高兴:
是否有一种解决方法可以让我使用presentViewController实现预期的行为?例如,root - > view2 - >厂景
对于实现理想的行为,还有哪些其他方法更实用?它/他们必须使用app委托,因为在我的实际应用中这将是不可避免的。
我是否通过尝试将视图控制器放在顶部而不集成到更大的架构中来破坏规则?例如,这种行为应该由导航控制器和推/弹出处理吗?如果是这样,你能解释为什么xCode不希望我这样做吗?为什么我不能只显示我想要的任何视图控制器,而不必与其他视图控制器有任何关系? (也许是因为这可能导致滥用应用代表?)
“呈现”视图控制器真正意味着什么?除了在演示者和演示者之间创建指针之外,还有哪些功能限制或功能?将呈现视图控制器保持“活动”的重要性是什么?
相反,如果让view1上的按钮发送presentViewController
消息到根视图(我希望它只是从根目录更改表示链 - > view1到root - > view2,让view1仍然存在于内存中但不属于此链的一部分),我得到一个不同的错误:“尝试在窗口层次结构中显示其视图!”这是什么意思?我找不到窗口层次结构的解释。
好的,我知道我在这里问了很多,但任何数量的启蒙都会受到高度赞赏!!
答案 0 :(得分: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控制,这就是你想要保持那个'活跃'的原因。当您发送此消息时:
[self dismissViewControllerAnimated:completion:]
,self
只是将信息重新路由到presentingViewController
。如果你摆脱了presentingViewController
,你的解雇方法将会中断。
上面回答了第5点。在询问底层视图出现之前,您需要首先关闭最顶层视图。请注意,view1“仍然在内存中”,但这只是因为您在应用委托中保留了指向它的指针。
更新
当您尝试使用初始启动 - 直接到view1时,您可以创建一个BOOL launched
属性并从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];
}
}
答案 1 :(得分:1)
让我试着逐一解决你的观点。
1)不,你不应该使用presentViewController。
2)如果你想做root - > view1 - > view2 - > view1,然后你不用presentViewController做所有。要从view1返回到view2,你应该使用dismissViewControllerAnimated:completion。
3)当你使用presentViewController:animated:时,视图控制器确实有关系。呈现控制器具有指向它所呈现的指针的指针,并且呈现的控制器具有指向呈现它的指针。所以,无论你是否愿意,你都会得到这些关系。有一种方法可以显示你想要的任何控制器而它们之间没有任何关系 - 只需重置窗口的根视图控制器即可。旧的视图控制器将被释放(如果你没有保持一个强大的指针),新的视图控制器将成为窗口的根视图控制器。
4)呈现视图控制器使该控制器成为模态视图控制器 - 它接管整个屏幕并且旨在用作应用程序流的中断。你真的不应该广泛使用它们从一个控制器转到另一个控制器(尤其不是“向后”转向以前的控制器)。由于它应该被使用的方式,你通常想要回到呈现它的控制器,这就是为什么它保持“活跃”(从某种意义上说它没有被释放)。
5)你得到那个错误,因为root的视图不在屏幕上,view1是。您需要在屏幕上显示控制器中的视图控制器。