質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • Swift

    7045questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

キャストができません UITabBarControllerからUIViewControllerへ

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 188
退会済みユーザー

退会済みユーザー

ModalViewController内にあるchangeButton(UIButton)をタップすると
クラッシュし、コンソールに
Could not cast value of type UITabBarController to HomeViewController(UIViewController)と表示されます。

遷移は

UITabBarController
↓
FirstViewController(UITableViewController) ※UITabBarController1タブ目のビューです
↓
HomeViewController(UIViewController)ModalViewController(UIViewController)


の順です。

クラッシュの原因は
コード内でUITabBarControllerとHomeViewControllerが繋がっていない=キャストできないからと思っていますが、キャスト方法がわからない為質問します。
見て頂けないでしょうか?

よろしくお願いします。

import UIKit


class CustomTabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.hidesBackButton = true

        // 1
        let firestoreController = FirestoreController()
        firestoreController.navigationItem.title = "タブ1"

        let firstNavigationController = UINavigationController(rootViewController: firestoreController)
        firstNavigationController.title = ""
        firstNavigationController.tabBarItem.image = UIImage(named: "a")


        viewControllers = [firstNavigationController]
        tabBar.isTranslucent = false
    }
}
import UIKit

class FirestoreController: UITableViewController {

    private var aButton: UIBarButtonItem!

        override func viewDidLoad() {

        self.navigationItem.hidesBackButton = true


        aButton = UIBarButtonItem(title: "ホーム", style: .plain, target: self, action: #selector(aaa))

        self.navigationItem.leftBarButtonItem = aButton

    }

    @objc func aaa(_ sender: AnyObject) {

        let vc = HomeViewController()
        navigationController?.pushViewController(vc, animated: true)

    }

}
import UIKit

class HomeViewController: UIViewController {


    var textFromModal = "" {
        didSet {

            updatelabel(text: textFromModal)
        }
    }


    var textLabel = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()

    view.backgroundColor = .white
    set()
    }


    func set() {


        textLabel = UILabel(frame: CGRect(x: 0, y: 0, width: view.bounds.width - 20, height: 30))
        textLabel.center = CGPoint(x: view.center.x, y: view.center.y - 50)
        textLabel.textAlignment = .center

        textLabel.text = ""
        view.addSubview(textLabel)

        //

        let modalButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
        modalButton.center = view.center
        modalButton.setTitle("開く", for: .normal)
        modalButton.setTitleColor(UIColor.blue, for: .normal)
        modalButton.addTarget(self, action: #selector(pushModal(sender:)), for: .touchUpInside)
        view.addSubview(modalButton)
    }



    @objc func pushModal(sender:UIButton) {

        let modal = ModalViewController(nibName: nil, bundle: nil)
       modal.modalTransitionStyle = .crossDissolve
        present(modal, animated: true, completion: nil)
    }



    func updatelabel(text: String) {
        textLabel.text = "a, \(text)"
    }


}
import UIKit

class ModalViewController: UIViewController, UITextFieldDelegate {


    var changeButton = UIButton()

    var textField = UITextField()

    override func viewDidLoad() {
        super.viewDidLoad()

        //


        view.backgroundColor = .gray


    let cancelButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
        cancelButton.center = CGPoint(x: view.center.x - 100, y: view.center.y)
        cancelButton.setTitle("キャンセル", for: .normal)
        cancelButton.setTitleColor(UIColor.black, for: .normal)
        cancelButton.addTarget(self, action: #selector(pushDismiss(sender:)), for: .touchUpInside)
        view.addSubview(cancelButton)


        //


        changeButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
        changeButton.center = CGPoint(x: view.center.x + 100, y: view.center.y)
        changeButton.setTitle("変更", for: .normal)
        changeButton.setTitleColor(UIColor.black, for: .normal)
        changeButton.addTarget(self, action: #selector(pushChange(sender:)), for: .touchUpInside)

        changeButton.isEnabled = false
        view.addSubview(changeButton)



        textField = UITextField(frame: CGRect(x: 0, y: 0, width: view.bounds.width - 20, height: 30))
        textField.center = CGPoint(x: view.center.x, y: view.center.y + 50)
        textField.delegate = self
        textField.text = ""
        textField.backgroundColor = .white
        view.addSubview(textField)



        let center = NotificationCenter.default
        center.addObserver(省略してます)
    }



    @objc func textFieldDidChange(notification: NSNotification) {

        if textField.text == "" {
            changeButton.isEnabled = false
        } else {
            changeButton.isEnabled = true
        }
    }



    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
       self.textField.delegate = self
    textField.resignFirstResponder()
       return true

    }


    @objc func pushChange(sender:UIButton) {

        textField.resignFirstResponder()

        let originVc = presentingViewController as! HomeViewController
          originVc.textFromModal = textField.text!

        self.dismiss(animated: true, completion: nil)
    }


    @objc func pushDismiss(sender:UIButton) {
        self.dismiss(animated: true, completion: nil)
    }

}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

presentingViewControllerは、一番基底となっているCustomTabBarControllerを返すので、HomeViewControllerにはキャストできません。

HomeViewControllerを取得するためには、UITabBarControllerからselectedViewControllerで現在選択されているViewControllerを取得し、これが、UINavigationControllerなので、さらにそこから、topViewControllerで最前面のViewControllerを取得することになります。

let tabVc = self.presentingViewController as! UITabBarController
let navigationVc = tabVc.selectedViewController as! UINavigationController
let originVc = navigationVc.topViewController as! HomeViewController
originVc.textFromModal = textField.text!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/25 00:20

    f-miyu様
    回答の仕組みが分かりやすくとても勉強になります。
    実現したい動作を確認できました。ありがとうございます。
    気になる点があります。

    >>ViewControllerを取得し、これが、UINavigationControllerなので
    これはUITabBarControllerのタブにセレクトするビュー(selectedViewController)は何でもUINavigationControllerになる,
    という事でしょうか?

    キャンセル

+1

UITabBarControllerselectedViewControllerで取得できるのも、基底となっているViewControllerです。
今回の場合は、FirstViewControllerUINavigationControllerの入れ子にして、そこから、HomeViewControllerに遷移している形なので、UINavigationControllerが取得されます。
UINavigationControllerの入れ子にせず、そのままViewControllerUITabBarControllerに追加した場合は、もちろんそのViewControllerが取得できます。


間違えて新たな回答として記述してしまいましたが、

ViewControllerを取得し、これが、UINavigationControllerなので
これはUITabBarControllerのタブにセレクトするビュー(selectedViewController)は何でもUINavigationControllerになる,
という事でしょうか?

に対するコメントです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/25 12:02

    今まで私は遷移の仕組みや入れ子を全くイメージができていませんでしたが、f-miyu様のお陰で、とても理解が深まり嬉しいです。
    沢山のヒントを頂きました。何度もありがとうございます!!

    キャンセル

  • 2018/07/04 13:21

    f-miyu様
    既に終了していますが、もし宜しければ是非教えて頂きたいです。

    f-miyu様の回答にある様な遷移の仕組みは、
    どちらのドキュメントを見て習得されたのでしょうか?apple公式サイトでしょうか?

    キャンセル

  • 2018/07/04 14:17

    もちろんドキュメントも見ますが、ある程度仕組みがわかったら、実際にやってみて試行錯誤することが多いです。今回の場合なら、UITabBarControllerやUINavigationControllerの仕様がこうであるから、HomeViewControllerを取得するためには、こうしないといけないかもなと考えて試してみるといった感じでしょうか。あまり役に立たない回答ですみません。

    キャンセル

  • 2018/07/04 15:10

    とんでもないです。
    f-miyu様のおかげで今回知ったことを応用し、presentedViewControllerで値を渡したりできました。理解したことで今までとは違う見方ができるようになり、一気に楽しくなりました。
    https://developer.apple.com/documentation/uikit/uitabbarcontroller?changes=_3
    TabBarControllerの構造はこのドキュメントに載っていました。仰っていた通りだったので、今後もっと理解できる気がします。
    きっかけを与えて頂き、ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Swift

    7045questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています