这行:
[self dismissViewControllerAnimated:YES completion:nil];
不是在向自己发送消息,而是在向其呈现的VC发送消息,要求其执行关闭操作。呈现VC时,将在呈现的VC和呈现的VC之间创建一种关系。因此,您不应在演示时破坏演示VC(演示的VC无法发回该关闭消息…)。由于您并未真正考虑到它,因此使应用程序处于混乱状态。请参阅我的回答“解散Presented View Controller
”,我建议在其中更清晰地编写此方法:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
在您的情况下,您需要确保所有控制都在中完成mainVC
。您应该使用委托将正确的消息从ViewController1发送回MainViewController,以便mainVC可以关闭VC1,然后显示VC2。
在VC2 VC1中,在.h文件中的@interface上方添加一个协议:
@protocol ViewController1Protocol <NSObject>
- (void)dismissAndPresentVC2;
@end
然后在@interface部分的同一文件中向下声明一个属性,以保存委托指针:
@property (nonatomic,weak) id <ViewController1Protocol> delegate;
在VC1 .m文件中,dismiss按钮方法应调用委托方法
- (IBAction)buttonPressedFromVC1:(UIButton *)sender {
[self.delegate dissmissAndPresentVC2]
}
现在在mainVC中,在创建VC1时将其设置为VC1的委托:
- (IBAction)present1:(id)sender {
ViewController1* vc = [[ViewController1 alloc] initWithNibName:@"ViewController1" bundle:nil];
vc.delegate = self;
[self present:vc];
}
并实现委托方法:
- (void)dismissAndPresent2 {
[self dismissViewControllerAnimated:NO completion:^{
[self present2:nil];
}];
}
present2:
可以与VC2Pressed:
按钮IBAction方法相同。请注意,它是从完成块中调用的,以确保在完全消除VC1之前不会显示VC2。
您现在正在从VC1-> VCMain-> VC2迁移,因此您可能只希望对其中一个过渡进行动画处理。
更新
在您的评论中,您对实现看似简单的事情所需的复杂性感到惊讶。我向您保证,这种委派模式对于Objective-C和Cocoa来说至关重要,而这个示例是您所能获得的最简单的示例,因此您确实应该努力使其满意。
在Apple的《View Controller编程指南》中,他们这样说:
消除呈现的视图控制器
当需要解散呈现的视图控制器时,首选方法是让呈现的视图控制器将其解雇。换句话说,只要有可能,呈现视图控制器的同一视图控制器也应负责解散它。尽管有多种技术可以通知呈现视图控制器其呈现的视图控制器应被取消,但首选技术是委派。有关更多信息,请参见“使用委托与其他控制器进行通信”。
如果您真正考虑了要实现的目标以及发展的方式,您将意识到向MainViewController传递消息以完成所有工作是您不想使用NavigationController的唯一逻辑出路。如果您确实使用了NavController,则实际上是在“委派”(即使不是显式地)navController来完成所有工作。需要有一个对象来始终跟踪VC导航的运行情况,并且无论您做什么,都需要某种与之通信的方法。
实际上,Apple的建议有点极端……在正常情况下,您无需建立专门的委托和方法,就可以依靠[self presentingViewController] dismissViewControllerAnimated:
-在这种情况下,您希望您的解雇对遥控器产生其他影响您需要注意的物品。
您可以想象在没有所有代表麻烦的情况下工作。
- (IBAction)dismiss:(id)sender {
[[self presentingViewController] dismissViewControllerAnimated:YES
completion:^{
[self.presentingViewController performSelector:@selector(presentVC2:)
withObject:nil];
}];
}
在要求演示控制器解雇我们之后,我们有一个完成模块,该模块调用presentingViewController中的方法来调用VC2。无需代表。(块的一大卖点是,在这种情况下,它们减少了对代表的需求)。但是,在这种情况下,有几件事会妨碍您...
- 在VC1中,您不知道mainVC实现了该方法
present2
-您最终会遇到难以调试的错误或崩溃。代表们可以帮助您避免这种情况。
- 一旦VC1被解雇,执行完成块就不是真正的事情了……或者是吗?self.presentingViewController不再有意义吗?您不知道(我也不知道)...与一位代表一起,您没有这种不确定性。
- 当我尝试运行此方法时,它只是挂起而没有警告或错误。
所以,请...花时间学习授权!
更新2
在您的评论中,您设法通过在VC2的关闭按钮处理程序中使用此命令来使其工作:
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
这当然要简单得多,但是会给您带来许多问题。
紧密耦合
您正在将viewController结构紧密地连接在一起。例如,如果要在mainVC之前插入一个新的viewController,则所需的行为将中断(您将导航至前一个)。在VC1中,您还必须#import VC2。因此,您有很多相互依赖关系,这违反了OOP / MVC目标。
使用委托,VC1和VC2都不需要了解mainVC或其前身,因此我们将所有内容保持松散耦合和模块化。
内存
VC1尚未消失,您仍然拥有两个指向它的指针:
- mainVC的
presentedViewController
财产
- VC2的
presentingViewController
属性
您可以通过登录进行测试,也可以通过VC2进行测试
[self dismissViewControllerAnimated:YES completion:nil];
它仍然有效,仍然可以使您回到VC1。
在我看来,这就像是内存泄漏。
提示是您到达此处的警告:
[self presentViewController:vc2 animated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
当您尝试关闭显示的VC时,逻辑崩溃了,其中VC2是显示的VC。第二条消息并没有真正执行-也许发生了一些事情,但是您仍然有两个指针指向您认为已经摆脱的对象。(编辑-我已经检查了这一点,它还不错,回到mainVC时两个对象都消失了)
这是一个相当漫长的说法-请使用委托。如果有帮助,我在这里对模式进行了另一个简短的描述:
在构造函数中传递控制器总是不好的做法吗?
更新3
如果您真的想避免委托,这可能是最好的出路:
在VC1中:
[self presentViewController:VC2
animated:YES
completion:nil];
但是不要解开任何东西……正如我们确定的那样,这实际上并没有发生。
在VC2中:
[self.presentingViewController.presentingViewController
dismissViewControllerAnimated:YES
completion:nil];
由于我们(知道)还没有退出VC1,因此可以通过VC1返回到MainVC。MainVC关闭VC1。由于VC1已经不存在,因此介绍了VC2以及它,因此您回到MainVC时处于干净状态。
它仍然是高度耦合的,因为VC1需要了解VC2,而VC2需要知道它是通过MainVC-> VC1到达的,但这是最好的方法,而无需进行任何明确的委派。