この行:
[self dismissViewControllerAnimated:YES completion:nil];
はそれ自体にメッセージを送信しているのではなく、実際にメッセージを提示しているVCに送信して、却下を行うように依頼しています。VCを提示するときは、提示しているVCと提示されているVCの間に関係を作成します。したがって、提示中のVCを破棄しないでください(提示されたVCはその却下メッセージを送り返すことはできません…)。あなたはそれを実際に考慮していないので、あなたはアプリを混乱した状態のままにしている。私の答えを参照してください。
この方法をより明確に書くことをお勧めする、提示されたビューコントローラの却下:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
あなたの場合、すべての制御がで行われるようにする必要がありますmainVC
。mainVCがVC1を閉じてから、VC2を提示できるように、デリゲートを使用して、ViewController1からMainViewControllerに正しいメッセージを送り返す必要があります。
ではVC2 VC1 @interface上記のあなたの.hファイル内のプロトコルを追加します。
@protocol ViewController1Protocol <NSObject>
- (void)dismissAndPresentVC2;
@end
@interfaceセクションの同じファイルで、デリゲートポインタを保持するプロパティを宣言します。
@property (nonatomic,weak) id <ViewController1Protocol> delegate;
VC1 .mファイルでは、却下ボタンメソッドはデリゲートメソッドを呼び出す必要があります
- (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から移動しているため、トランジションの1つだけをアニメーション化する必要があります。
更新
あなたのコメントでは、一見単純なことを達成するために必要な複雑さに驚きを表明しています。確かに、この委任パターンは、Objective-CとCocoaの多くの中心であり、この例は、入手できる最も単純なものであるため、実際に慣れるために努力する必要があります。
AppleのViewControllerプログラミングガイドでは、次のように述べています。
提示されたViewControllerを閉じる
提示されたビューコントローラを却下するときが来たとき、好ましいアプローチは、提示されたビューコントローラにそれを却下させることです。言い換えると、可能な場合は常に、ViewControllerを提示したのと同じViewControllerがそれを却下する責任を負う必要があります。提示されたビューコントローラを却下する必要があることを提示するビューコントローラに通知するためのいくつかの手法がありますが、推奨される手法は委任です。詳細については、「委任を使用した他のコントローラーとの通信」を参照してください。
何を達成したいのか、そしてそれをどのように進めているのかを本当に考えれば、NavigationControllerを使用したくない場合は、MainViewControllerにメッセージを送信してすべての作業を実行することが唯一の論理的な方法であることがわかります。あなたがいる場合やるから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はもう何か意味がありますか?あなたは知りません(私も知りません)...代理人と一緒に、あなたはこの不確実性を持っていません。
- このメソッドを実行しようとすると、警告やエラーなしでハングします。
だからお願いします...代表団を学ぶために時間をかけてください!
update2
あなたのコメントでは、VC2の却下ボタンハンドラーでこれを使用することにより、それを機能させることができました:
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
これは確かにはるかに簡単ですが、多くの問題が残ります。
密結合
viewController構造を一緒にハードワイヤリングしています。たとえば、mainVCの前に新しいviewControllerを挿入すると、必要な動作が中断されます(前の動作に移動します)。VC1では、VC2を#importする必要もあります。したがって、相互依存関係が非常に多く、OOP / MVCの目標が達成されません。
デリゲートを使用すると、VC1もVC2も、mainVCまたはその前身について何も知る必要がないため、すべてを疎結合でモジュール化した状態に保ちます。
メモリ
VC1は消えていません、あなたはまだそれへの2つのポインタを持っています:
- mainVCの
presentedViewController
プロパティ
- VC2の
presentingViewController
プロパティ
これは、ロギングによってテストできます。また、VC2からこれを実行するだけでもテストできます。
[self dismissViewControllerAnimated:YES completion:nil];
それはまだ機能し、VC1に戻ります。
それはメモリリークのように私には思えます。
これの手がかりはあなたがここに来ている警告にあります:
[self presentViewController:vc2 animated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
VC2が提示されたVCである提示VCを却下しようとすると、ロジックが機能しなくなります。2番目のメッセージは実際には実行されません-おそらくいくつかのことが起こりますが、それでも、削除したと思ったオブジェクトへの2つのポインターが残っています。(編集-私はこれをチェックしましたが、それほど悪くはありません。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経由で到着したことを知る必要があるため、依然として高度に結合されていますが、明示的な委任を少し行わずに取得するのが最善です。