2012 年 8 月更新:
iOS 5 及更高版本引入了更安全的 API 来执行操作after使用完成块将模态动画移入/移出位置:
[self presentViewController:myModalVC animated:YES completion:^{}];
[self dismissViewControllerAnimated:YES completion:^{}];
2012 年 8 月前答复:
当我忽略模态一然后快速连续地呈现模态二时,我遇到了类似的问题。有时情态二会在情态一被消除后显示,有时情态二根本不会出现,这让我非常难过。
对我来说看起来像是一个竞争条件......
对呈现模态二的方法的调用者施加 1+ 秒的延迟,showModalTwo
,使模态二在模态一被消除后每次出现:
- (void)didDismissModalOne {
[self performSelector:@selector(showModalTwo:)
withObject:someNumber
afterDelay:1.0f];
}
这证实了一种怀疑,即模态一的消除和模态二的呈现之间存在某种竞争条件。然而,对调用者施加延迟是不优雅的,并且不能保证竞争条件在其他情况下不会再次出现。
问题
事实证明UIViewController
拥有公共财产,modalViewController
,当presentModalViewController:animated:
被调用并拆除时dismissModalViewControllerAnimated:
叫做。问题是它不会被同步拆除,因此有可能在删除旧值之间产生竞争modalViewController
并按以下方式设置新值。
- 现在情态一。
myViewController.modalViewController
现在指向模态一
- 驳回模态一。要拆除的后台进程
myViewController.modalViewController
已经开始了,但是myViewController.modalViewController
仍然指向模态一
- 现在情态二,
myViewController.modalViewController]
现在指向模态二
- 系统回调触发,设置
myViewController.modalViewController
to nil
,这会中断模态二动画的过程,结果是用户永远看不到它。
比赛从第 2 步开始,并在第 4 步显现。
解决方案
我的解决方案是在呈现模态二的方法上设置一个保护条件,以确保myViewControoler.modalViewController
was 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
is nil
。只有这样,弹出模态二才是“安全”的。