理論的な質問があります。現在、Appleの ViewController ガイドを読んでいます。
彼らが書きました:
提示されたView Controllerを却下するときが来るとき、望ましいアプローチは提示View Controllerにそれを却下させることです。つまり、可能な場合は、View Controllerを表示した同じView Controllerも、それを破棄する責任を負う必要があります。表示中のView Controllerを削除する必要があることを表示中のView Controllerに通知する方法はいくつかありますが、推奨される方法は委任です。
しかし、単純な呼び出しではなく、提示されたVCでプロトコルを作成し、デリゲート変数を追加し、提示されたVCを破棄するためにVCを提示するデリゲートメソッドを作成する必要がある理由を説明できませんinpresentedView Controllerメソッド
[self dismissViewControllerAnimated:NO completion:nil]
?
最初の選択の方が良いのはなぜですか?なぜAppleが推奨するのですか?
ここでは、Appleが、陰鬱なAPIの可能性のために、彼らの背中を少し覆っていると思います。
[self dismissViewControllerAnimated:NO completion:nil]
実際にはちょっとしたフィドルです。正当に-提示されたView Controllerでこれを呼び出すことができますが、メッセージを提示しているView Controllerに転送するだけです。 VCを却下するだけでなく、何でもやりたい場合は、これを知る必要があり、デリゲートメソッドとほぼ同じように扱う必要があります。デリゲートメソッド。
おそらく彼らは、これがどのように組み立てられているのかを本当に理解していない人々によって大量の悪いコードに出くわしたので、彼らの警告です。
しかし、もちろん、あなたがする必要があるのがその事を却下するだけなら、先に進んでください。
私自身のアプローチは妥協であり、少なくとも何が起こっているのかを思い出させます:
[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil]
[Swift]
self.presentingViewController?.dismiss(animated: false, completion:nil)
これは、View Controllerの再利用性のためです。
View Controllerは、モーダルとして表示されるのか、Navigation Controllerにプッシュされるのか、その他何でもかまいません。 View Controllerが閉じている場合、モーダルで表示されているとみなされます。そのView ControllerをNavigation Controllerにプッシュすることはできません。
プロトコルを実装することにより、親View Controllerに、それをどのように提示/プッシュおよび破棄/ポップするかを決定させることができます。
Swift 3に更新
ここに来たのは、現在の(提示された)View Controllerを閉じたいだけです。私は同じ目的でここに来る人のためにこの答えを作っています。
Navigation Controllerを使用している場合、それは非常に簡単です。
前のView Controllerに戻ります:
// Swift
self.navigationController?.popViewController(animated: true)
// Objective-C
[self.navigationController popViewControllerAnimated:YES];
ルートView Controllerに戻ります:
// Swift
self.navigationController?.popToRootViewController(animated: true)
// Objective-C
[self.navigationController popToRootViewControllerAnimated:YES];
(Objective-Cの この回答 に感謝します。)
View Controllerがモーダルで表示されている場合は、次の呼び出しにより(2番目のView Controllerから)それを閉じることができます
// Swift
self.dismiss(animated: true, completion: nil)
// Objective-C
[self dismissViewControllerAnimated:YES completion:nil];
ドキュメント は、
表示するView Controllerは、表示するView Controllerを削除します。提示されたView Controller自体でこのメソッドを呼び出すと、UIKitは提示されたView Controllerに却下の処理を要求します。
そのため、提示されたView Controllerがそれ自体で呼び出すために機能します。 ここ は完全な例です。
OPの質問は、デリゲートを使用してビューを却下する複雑さに関するものでした。
通常、Navigation ControllerまたはモーダルView Controllerがあるため、ここまでデリゲートを使用する必要はありませんが、将来的に デリゲートパターン を使用する必要がある場合は、更新を追加します。
私の経験では、any必要なViewControllerから破棄し、それぞれに異なるタスクを実行する必要がある場合に役立ちますそれを却下するviewcontroller。プロトコルを採用するviewControllerは、独自の方法でビューを閉じることができます。 (ipadとiphone、または異なるビューから閉じるときに異なるデータを渡す、閉じるときに異なるメソッドを呼び出すなど)
編集:
したがって、明確にするために、ビューを閉じたいだけなら、デリゲートプロトコルを設定する必要はないと思います。別のことを行う必要がある場合after表示する別のView Controllerから削除します。デリゲートを使用します。
これを試して:
[self dismissViewControllerAnimated:true completion:nil];
1つのポイントは、これが優れたコーディングアプローチであることです。 SRP、懸念の分離など、多くのOOP
原則を満たします。
したがって、ビューを表示するView Controllerは、それを却下する必要があります。
同様に、家賃を支払う不動産会社は、家を取り戻す権限を持つべきです。
Swift 3. // SwiftでView Controllerを閉じる
self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
ビューからの引用 Controller Programming Guide 、「View Controllerが他のView Controllerをどのように提示するか」。
提示されたView Controllerのチェーン内の各View Controllerには、チェーン内でそれを囲む他のオブジェクトへのポインタがあります。つまり、別のView Controllerを表示する表示されたView Controllerは、presentingViewControllerプロパティとpresentedViewControllerプロパティの両方に有効なオブジェクトを持っています。これらの関係を使用して、必要に応じてView Controllerのチェーンをトレースできます。 たとえば、ユーザーが現在の操作をキャンセルした場合、最初に表示されたView Controllerを閉じることにより、チェーン内のすべてのオブジェクトを削除できます。 View Controllerを閉じると、そのView Controllerだけでなく、それが表示したView Controllerもすべて閉じられます。
そのため、一方ではナイスバランスの取れたデザイン、優れたデカップリングなどが可能になります。しかし、他方では、ナビゲーションの特定のポイントにすばやく戻ることができるため、非常に実用的です。
ただし、個人的には、巻き戻しセグエを使用して、表示ビューコントローラツリーを逆方向にたどろうとするのですが、これはAppleこの章では、引用元を説明しています。
マイケルエンリケスの答えに加えて、これが不確定な状態から身を守る良い方法かもしれない別の理由を考えることができます。
ViewControllerAがViewControllerBをモーダルに提示するとします。ただし、ViewControllerAのコードを記述していない可能性があるため、ViewControllerAのライフサイクルを認識していません。 ViewController、ViewControllerBを提示してから5秒後に(たとえば)却下する場合があります。
この場合、ViewControllerBのdismissViewController
を単に使用して自分自身を閉じると、未定義の状態になります。クラッシュや黒い画面ではなく、視点からは未定義の状態になります。
代わりに、デリゲートパターンを使用している場合は、ViewControllerBの状態を認識し、説明したようなケース用にプログラムできます。
Swift
let rootViewController:UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!
if (rootViewController.presentedViewController != nil) {
rootViewController.dismiss(animated: true, completion: {
//completion block.
})
}
モーダルを使用している場合は、表示を閉じます。
[self dismissViewControllerAnimated:NO completion:nil];
スーパービューウィンドウを閉じることができます
self.view.superview?.window?.close()
これはたくさんのワニです。委任は必要な場合は問題ありませんが、コードをより複雑にする場合(そして複雑になる場合)、その理由が必要です。
Appleにはその理由があると確信しています。しかし、他の方法で真の理由がない限り、単に提示されたVCを却下するほうが明確で簡潔です。
プロトコルは必要なときに優れていますが、オブジェクト指向の設計では、モジュールが互いに不必要に通信することは決してありませんでした。
Tom Love(Objective Cの共同開発者)はかつて、Objective Cは「エレガント」、「スモール」、「クリスプ」、「明確」(C++と比較した場合)であるとコメントしました。彼が言うのは簡単です。委任は「理由」で使いすぎたように思われる便利な機能であり、私は言語での作業が好きである一方で、不必要な構文を使用して物事を必要以上に複雑にすることを余儀なくされるという考えを恐れています。