web-dev-qa-db-ja.com

埋め込みビューコントローラへのIBOutletリンク

複数のビューコントローラーを使用して管理する複雑なiPadビューがあります。私は以前(iOS6/XCode 4.5より前)、コードでビューコントローラーを割り当てることでこれを行い、マスタービューへのリンクを介してさまざまなビューをフックしました。

私がやりたいことは、新しいコンテナビューを使用して、ストーリーボードファイルにビューコントローラを埋め込むことです。埋め込みコントローラーからマスターコントローラーへのIBOutletリンクを作成できないようです。

これは可能ですか?または、コード内のタグまたは何かを介して組み込みコントローラーを取得するには?

この質問は、特にコンテナビューの使用に関するものです

36
Dan F

「組み込みコントローラーを取得する」という意味がわかりません。コントローラーを使用する場合は、UIStoryboardメソッドのinstantiateViewControllerWithIdentifier:を使用し、IBでコントローラーに指定した識別子を使用します。また、performSegueWithIdentifier:sender:メソッドを使用することもできます(これにより、ビューコントローラもインスタンス化されます)。 Apple docsの「アプリでのビューコントローラーの使用」セクションを確認してください。子ビューコントローラーがコンテナーコントローラーと同時にインスタンス化されるという事実にも言及しています。

編集後:コンテナービューを別のビューコントローラーに埋め込む場合、その埋め込みビューのコントローラーは、それを含むコントローラーからself.childViewControllersで参照できます(配列になるため、1つしかない場合は、lastObjectで取得できます)。 。

22
rdelmar

場合によっては、-prepareForSegue:sender:を使用して組み込みコントローラーをキャプチャするというオプションもあります。

たとえば、UINavigationControllerCustomContainerViewControllerを埋め込んでいる場合、ストーリーボードで埋め込みセグエにembedContentStackという名前を付けて、CustomContainerViewControllerにキャプチャすることができます。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"embedContentStack"]) {
        // can't assign the view controller from an embed segue via the storyboard, so capture here
        _contentStack = (UINavigationController *)segue.destinationViewController;
    }
}
71
PlayfulGeek

これに関する別のスレッドを次に示します。 親iOSからContainer View Controllerにアクセス

参照を prepareForSegue に保持するか、または埋め込まれたviewControllerを self.childViewControllers で検索することを提案します

3
theguy

注意事項

この質問への回答の使用に進む前に、埋め込まれたものが本当にビューコントローラーである必要があるかどうかを反映したい場合があります。

たとえば、UICollectionViewControllerサブクラスを埋め込む場合、代わりにUICollectionViewサブクラスを埋め込むことができますか?または、さらに良いことに、UIViewサブクラスを埋め込んで、UICollectionViewを単純なViewModelの背後に隠すことができますか?

現在取り組んでいるコードベースで、2つのビューコントローラーを別のビューコントローラーに埋め込みます。どちらもかなり簡単に単純なビューになり、この面倒なコードがなければ、ストーリーボードでより簡単にバインドできます。

残念ながら、それらは現在ビューコントローラーであり、私は現在それらをプレーンビューに単純化する立場にないので、これを行う必要があります。

バックグラウンド

Playful Geek で提案されているように、prepare(for segue:, sender:)の埋め込みセグエを取得する方法を使用しています。

Swiftこれはかなり整頓されているように見えるので、私はこれに使用しています...

class EditionLandingViewController: UIViewController {
    fileprivate var titlesView: SectionTitlesViewController!
    fileprivate var sectionsView: SectionsViewController!
}

//MARK:-

extension EditionLandingViewController {
    private enum SegueId: String {
        case embedTitles
        case embedSections
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)

        guard
            let segueRawId = segue.identifier,
            let segueId = SegueId(rawValue: segueRawId)
            else { return }

        switch segueId {
        case .embedTitles:
            self.titlesView = segue.destination as! SectionTitlesViewController

        case .embedSections:
            self.sectionsView = segue.destination as! SectionsViewController
        }
    }
}

討論

私は アクションメソッドとしての名前セグエ を選択しました。

セグエ識別子にenumケースを使用することは、コンパイラとツールを自分の側に持っていることを意味するため、セグエ名を間違って取得することははるかに困難です。

セグエIDをprivate enumextensionスコープ内の_は、これらのセグエが他のどこにも必要ないため、この場合は適切と思われます(たとえば、performedにすることはできません)。

埋め込みビューコントローラーに暗黙的にラップされていない型を使用しています。なぜなら、(いずれにしても)欠落している場合は論理エラーだからです。

同様に、宛先のビューコントローラタイプを強制的にキャストしてもかまいません。繰り返しますが、これらのタイプが同じでない場合は、論理エラーになります。

0
Benjohn