読者です 読者をやめる 読者になる 読者になる

Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 955 - セグエが変われば戻り方も変更

NavigationControllerを組み込んだTableViewControllerからViewControllerに遷移(セグエ)した場合、Cancelボタンの挙動を考えないとちゃんと動かない。分かったつもりでも納得できない自分がいたんでちょっと勉強(^_^;)

f:id:yataiblue:20170406112845j:plain

チュートリアルを読み飛ばしていたら混乱した部分が出てきたんで勉強しました。右上のMealViewController上で、「Cancel」ボタンが押した場合、セグエ元が2カ所あるんで挙動を考えないといけません。

左上のMealTableViewControllerに埋め込んでいるNavigationControllerのBar Button Itemの「+」が押された時はModallyにNavigationControllerが作られてMealViewControllerを表示していることになります。

ここで考えなければならないインスタンス・プロパティが、presentingViewControllerです。

presentingViewController

ViewControllerを「Presented Modally」で遷移させると「present(_:animated:completion:) 」メソッドでViewControllerを作成することになるけど、ストーリーボードでセグエを作っているとこのメソッドは見えてきません。

presentingViewControllerプロパティはpresent(_:animated:completion:) メソッドを使って表示されるViewControllerがセットされます。もしこのメソッド以外の遷移をした場合、1つ前のViewControllerがセットされたままになります。遷移前のViewControllerが存在しなければ「nil」を持つようです。

ということは上の例で「+」を押したときに「present(_:animated:completion:) 」を使ってMealViewControllerが表示されました。実際はNavigationControllerに載っかったMealViewControllerなんで次のBool型は「true」ということになります。

let isPresentingInAddMealMode = 
    presentingViewController is UINavigationController

そしてModallyに遷移したVIewControllerを消すメソッドはdismiss()メソッドになり次のように処理できます。

if isPresentingInAddMealMode {
            
            dismiss(animated: true, completion: nil)
}

では、MealTableViewControllerのCellを選択して遷移させた場合、セグエは「Show」になるため「prepare()」メソッドは使われなかったことになります。presentingViewControllerにはMealTableViewControllerがセットされ、if節の外に外れます。

じゃあ次にセグエがShowの場合、新しいMealViewControllerが作らているけど、元に持っているNavigationControllerの上にMealViewControllerをスタックして積み上げているので、navigationControllerプロパティを持っているはずです。条件式を次のようにすればいいんでしょう。

 } else if let owningNavigationController = 
                                  navigationController {
            
        owningNavigationController.popViewController(animated: true)
            
 }

popViewController(animated:)

このメソッドはNavigationControllerが持っているメソッドで、一番上のスタックを消し去って再表示させます。まさに新しいスタックを作った時のキャンセルにぴったりです。

そして最後にそれ以外の条件ならエラーにします。

} else {
            
    fatalError("The MealViewController 
          is not inside a navigation controller.")
            
}

こう書いたけどしっくりしないな(^_^;)