2012 年 8 月更新:
iOS 5 及更高版本引入了更安全的 API 来处理模态使用完成块动画进入/退出位置:
[self presentViewController:myModalVC animated:YES completion:^{}];
[self dismissViewControllerAnimated:YES completion:^{}];
2012 年 8 月之前的答案:
我在关闭模态一然后快速连续呈现模态二时遇到了类似的问题。有时候情态二会在情态一被解散后显示,有时候情态二根本不会出现,这让我很伤心。
对我来说看起来像是一种竞争条件......
在显示模态二 showModalTwo 的方法的调用者上放置 1 秒以上的延迟,使模态二在模态一被解除后每次出现:
- (void)didDismissModalOne {
[self performSelector:@selector(showModalTwo:)
withObject:someNumber
afterDelay:1.0f];
}
这证实了一种怀疑,即在模态一的解雇和模态二的呈现之间存在某种竞争条件。然而,延迟调用者是不雅的,并且不能保证竞争条件在其他情况下不会再次出现。
问题
原来UIViewControllers 有一个公共属性modalViewController,它在presentModalViewController:animated: 被调用时被设置,在dismissModalViewControllerAnimated: 被调用时被拆除。问题是它不会被同步拆除,因此可能会在删除 modalViewController 的旧值和通过以下方式设置新值之间产生竞争。
- 当前模式一。
myViewController.modalViewController 现在指向模态一
- 关闭模式一。后台进程拆除
myViewController.modalViewController已经开始,但myViewController.modalViewController仍然指向模态一
- 当前模态二,
myViewController.modalViewController] 现在指向模态二
- 系统回调触发,将
myViewController.modalViewController设置为nil,这会中断模态二动画的过程,结果是用户永远看不到它。
比赛从第 2 步开始,在第 4 步显现。
解决方案
我的解决方案是在呈现模态二的方法上设置一个保护条件,以确保在尝试呈现模态二之前 myViewControoler.modalViewController 是 nil。
-(void)showModalTwo:(NSNumber *)aParameter {
if (self.modalViewController) {
[self performSelector:@selector(showModalTwo:)
withObject:aParameter
afterDelay:0.1f];
return;
}
// You can now present the second modal safely.
}
工作就像一个魅力。更优雅的解决方案可能包括超时。
发布脚本
我真的不喜欢这个解决方案的轮询方面。 @Nimrod 建议,在这个问题的公认答案中,您可以从模态一的 viewDidDisappear: 方法安全地启动模态二的呈现。我喜欢这种事件驱动方法的声音,但是在我的用例中进行了完整的实现之后,我确认在使用viewDidDisappear: 中的回调呈现模态二时,竞争条件仍然存在。绝对确定将呈现模态二的唯一方法是在父视图控制器中进行轮询,直到您完全确定 self.modalViewController 是 nil。只有这样,弹出模态二才“安全”。