The Pragmatic Ball boy

iOSを中心にやってる万年球拾いの老害エンジニアメモ

popToRootViewControllerで画面を消すとviewWillDisappearでnavigationControllerがnilになる

現象が伝えにくいので、図に表すと以下のような感じで、 TabbarController内にNavigationControllerをもたせた状態で、いくつかViewControllerをPushViewControllerします。 そして、2つ以上PushViewControllerした状態で一番上のViewControllerのナビバーを透明にした場合にちょっと問題が発生します。

f:id:yanamura:20161208104925p:plain

一番上のViewControllerでは以下のようにして、ナビバーを透明にして、消すときにナビバーを元に戻す用にしています。

class SampleViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        navigationController?.navigationBar.shadowImage = UIImage()
        navigationController?.navigationBar.isTranslucent = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
        navigationController?.navigationBar.shadowImage = nil
        navigationController?.navigationBar.isTranslucent = false
    }
}

普通に戻るボタンを押した場合はこれで正常に動作するのですが、 タブバーのボタンをタップしてrootviewcontrollerに戻った場合に、viewWillDisappearが呼ばれたときにはnavigationControllerがnilになっているため、ナビバーが透明なままになってしまうという問題が発生しました。。

対策

その1

やっつけ仕事感のある対応としてはnavigationControllerを自力で保持するというやりかたで、、

    private weak var toKeepNavigationController: UINavigationController?

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        toKeepNavigationController = navigationController

        navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        navigationController?.navigationBar.shadowImage = UIImage()
        navigationController?.navigationBar.isTranslucent = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        toKeepNavigationController?.navigationBar.setBackgroundImage(nil, for: .default)
        toKeepNavigationController?.navigationBar.shadowImage = nil
        toKeepNavigationController?.navigationBar.isTranslucent = false
    }

その2

willMoveToParentViewControllerの時点ではnavigationControllerはnilになっていないようだったので、ViewControllerが消えるタイミング(parentがnilになったとき)にナビバーをもとにもどします

    override func willMove(toParentViewController parent: UIViewController?) {
        super.willMove(toParentViewController: parent)
        if parent == nil {
            navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
            navigationController?.navigationBar.shadowImage = nil
            navigationController?.navigationBar.isTranslucent = false
        }
    }

たぶん2のほうがいいと思います!

おかしいぞとかあればツッコミお願いします!