モーダルビューコントローラーを閉じてすぐに別のビューコントローラーを表示していますが、後者は発生しません。これがコードです:
[self dismissModalViewControllerAnimated:YES]; UIImagePickerController * picker = [[UIImagePickerController alloc] init]; picker.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; [self presentModalViewController:picker animated:YES];
最初のモーダルVCは下にスライドしますが、新しいpicker
は表示されません。何が起こっているのかについてのアイデアはありますか?
他のアニメーションのものと同様に、dismissModalViewControllerAnimated
は、ビューコントローラが消えるまでブロックしません。代わりに、それはビューコントローラの却下を「キックオフ」します。親ビューコントローラーでviewDidDisappear
のようなものを呼び出すモーダルコントローラー1のmodalViewControllerDisappeared
でコールバックを使用する必要がある場合があります。その方法では、モーダルコントローラー2を提示します。それ以外の場合は、ロボットKが言ったことです。
2012年8月更新:
iOS 5以降では、完了ブロックを使用してモーダルが /の場所でアニメーション化された後で、より安全なAPIが導入されています。
[self presentViewController:myModalVC animated:YES completion:^{}];
[self dismissViewControllerAnimated:YES completion:^{}];
2012年8月以前の回答:
モーダル1を閉じてからモーダル2を続けて表示すると、同様の問題が発生しました。モーダル1が却下された後にモーダル2が表示されることもあれば、モーダル2がまったく表示されないこともあり、とても悲しかったです。
モーダル2を提示したメソッドの呼び出し元にshowModalTwo
を1秒以上遅延させると、モーダル1が閉じられた後、毎回モーダル2が表示されます。
- (void)didDismissModalOne {
[self performSelector:@selector(showModalTwo:)
withObject:someNumber
afterDelay:1.0f];
}
これは、モーダル1の却下とモーダル2の提示の間に何らかの競合状態があったという疑いを確認しました。ただし、呼び出し側に遅延を設けることは洗練されておらず、他の状況下で競合状態が再発しないことを保証するものではありませんでした。
UIViewController
sには、presentModalViewController:animated:
が呼び出されたときに設定され、dismissModalViewControllerAnimated:
が呼び出されたときに破棄されるパブリックプロパティmodalViewController
があることがわかります。問題は、同期的に破棄されないことです。そのため、modalViewController
の古い値を削除してから、次の方法で新しい値を設定するまでの間に競合が発生する可能性があります。
myViewController.modalViewController
がモーダル1を指すようになりましたmyViewController.modalViewController
を破棄するバックグラウンドプロセスが開始されましたが、myViewController.modalViewController
はまだモーダルをポイントしていますmyViewController.modalViewController]
がモーダル2を指すようになりましたmyViewController.modalViewController
をnil
に設定します。これにより、モーダル2がアニメートするプロセスが中断され、ユーザーが目にすることはありません。レースはステップ2から始まり、ステップ4に現れます。
私の解決策は、モーダル2を表すメソッドにガード条件を設定して、モーダル2を表す前に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は、この質問に対する受け入れられた回答で、モーダル1のviewDidDisappear:
メソッドからモーダル2のプレゼンテーションを安全に開始できることを示唆しています。このイベントドリブンアプローチのサウンドは気に入りましたが、私のユースケースで完全な実装を行った後、viewDidDisappear:
内のコールバックを使用してモーダル2を提示すると、競合状態が持続することを確認しました。モーダル2が表示されることを確実に確認する唯一の方法は、self.modalViewController
がnil
であることが確実にわかるまで、親View Controller内でポーリングすることです。そのときだけ、モーダル2をポップしても「安全」です。
[self dismissViewControllerAnimated:YES completion:^{
//Present the new MVC
}];
注:iOS 5.0以降で利用できます。
[self dismissModalViewControllerAnimated:NO];
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
[self presentModalViewController:picker animated:YES];
何が起こっているのかというと、アニメーションを閉じると、ビューコントローラーがモーダルビューコントローラーへの参照を削除するためです。これは、このコードが呼び出された後に行われるため、モーダルで表示する新しいビューコントローラーがあるとは考えられません。
これに対処するには、didDismissModalVC
を呼び出した後、YES
ivarをdismissModalViewController
に設定します。それから私のviewDidAppear:
メソッドでは、ivarの値を確認し、新しいモーダルビューコントローラーを表示しています。 (値をNO
に戻すことも忘れないでください。そうすれば、永久にモーダルビューコントローラーを閉じてしまうのを防ぐことができます。)
この場合、2番目のモーダルビューコントローラーを表示するために、デリゲートからコールバックの親ビューコントローラーを作成します。
親View Controllerの定義プロトコル:
@protocol ParentViewControllerDelegate
- (void)showModalTwo;
@end
このプロトコルを親ビューコントローラーに実装して2番目のモーダルビューコントローラーを表示し、最初のモーダルビューコントローラーにデリゲートプロパティ@property id<ParentViewControllerDelegate> delegate;
を作成します。
親ビューコントローラーから最初のモーダルビューコントローラーを表示します。
TheFirstModalViewController *controller = ...
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
...
最初のモーダルビューコントローラーのviewDidDisappear:
メソッドでdelegate.showModalTwo:
を呼び出すだけで、親ビューコントローラーの2番目のモーダルビューが表示されます。
この助けを願っています。
IOS 10でうまく機能するように見える私のアプローチを以下に示します。私の状況は少し異なりますが、ほとんどの状況で機能するはずです。最初のviewControllerを、モーダルなviewControllerをすぐに表示する必要があるポップオーバーとして表示しています。
まず、最初のviewControllerのviewDidLoad
でビューを非表示にします。
view.isHidden = true
次に、viewWillAppear
で、モーダルのビューコントローラーをアニメーション化せずに表示し、完了時にビューを再表示します。
present(yourModalViewController, animated: false) { [unowned self]
self.view.isHidden = false
}
Bool
への後続の呼び出しでモーダルが再表示されないようにviewWillAppear
を使用して状態を制御することをお勧めしますが、アイデアは得られます。
Swiftの場合:
DismissViewControllerは次のようになります。
var presentingVC_Delegate: mainLists_PopoverDelegation!
@IBAction fund button_Pressed (sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: { finished in
self.presentingVC_Delegate.presentOtherVC()
print("DismissVC completion block says hello")
})
}
MainVCがpresentOtherVCを格納する場所:
func presentSettingsVC () {
self.performSegueWithIdentifier("present_OtherVC", sender: nil)
}