iOS 7向けアプリ開発時の注意点
iOS 7向けにアプリを開発していて気付いた注意点を備忘録を兼ねてまとめたいと思います。
間違いがありましたならばご指摘下さい。
iOS 7は大幅に設計し直したせいか、おかしな動きをする、いわゆるバグが大量にある感じです。
例えば以下の様な点です。
- UITextViewで改行のみの選択をしようとすると失敗する
- UITextView、UITextFieldの選択範囲の描画がおかしい
- UINavigationControllerのUIViewControllerのスタックが無限ループする
まあ、バグは兎も角として、まずは「UINavigationControllerのUIViewControllerのスタックが無限ループする」原因となった注意点を説明したいと思います。
UINavigationControllerのUIViewControllerのスタックが無限ループする
iOS 7から画面の上部だけではなく下部をスワイプすると様々な操作ができる様になりました。
アプリの上下をスワイプする事で勝手にOSの機能が動作してしまうので、アプリの操作の邪魔になるというのは置いておいて、左端を右にスワイプすると前の画面に戻れる機能も何気に追加されています。
この「画面の左端を右にスワイプすると前の画面に戻れる機能」ですが、UINavigationControllerにpushViewControllerしたUIViewControllerで使える様です。
勿論、今まで通り、UINavigaionbarを表示していれば自動的に左側に「戻る」ボタンが表示されます。
今までと違うのは、「画面の左端を右にスワイプすると前の画面に戻れる機能」で、少しでも前の画面を表示させると UIViewController@viewWillAppear:animated メソッドが呼び出されてしまう事です。
しかも、困った事に画面の左端を少し右にスワイプしてすぐに左にスワイプすると前の画面に戻るのをキャンセルできるのです。
このキャンセルがされると表示されると思って処理をした前の画面のUIViewController@viewWillAppear:animated メソッド内の処理が走ってしまうので場合によっては嬉しくない事も起こるかと思います。
ウチの場合は、UINavigationControllerのUIViewControllerのスタックが無限ループし、「戻る」ボタンでは前の画面に永遠に戻れなくなりました。
なお、右にスワイプでは戻れました。
この無限ループのパターンは非常にレアケースですが、以下の条件が揃うと出る様です。
BugReportは送付済みです。
- UINavigationControllerで表示している最初の画面にUINavigaionbarを表示していない。
- 最初の画面のUIViewController@viewWillAppear:animated メソッドでUINavigaionbarとUIToolbarを非表示にしている。
- 2番目の画面(UIViewController)ではUINavigaionbarを表示している。
- 2番目の画面で、右にスワイプで前の画面を少し表示してキャンセルする。
- 2番目の画面から3番目の画面(UIViewController)に 移動。
- 3番目の画面で「戻る」ボタンを押すとタイトルは2番目の画面のものになるが、永遠に戻れない。(ただし、右にスワイプでは戻れる)
問題の原因になっているのは「最初の画面のUIViewController@viewWillAppear:animated メソッドでUINavigaionbarとUIToolbarを非表示にしている。」です。UIViewController@viewDidAppear:animated メソッドで行えば問題ない様です。
少し別画面から戻って来た時の表示が乱れますが、無限ループするよりはマシでしょう。
2013/10/07追記
左端をスワイプすると前の画面のUIViewController@viewWillAppear:animatedメソッドが呼び出されます。
そしてスワイプで前画面に戻る操作をキャンセルするとUIViewController@viewWillDisappear:animatedメソッドが呼び出されます。
つまり、キャンセルするとUIViewController@viewDidAppear:animatedメソッドは呼び出されません。
ライフサイクル的には正しいのですが、戻る操作のキャンセルというのは今までに無い動作なので、きちんと想定しておかないといけないですね。
ステータスバーについて
iOS 7ではステータスバーに関係する座標の扱いが変わり、今まで通りUIView等をY座標を0にしているとステータスバーの下になってしまいます。
- ステータスバーを表示/非表示にするには UIViewController@prefersStatusBarHidden メソッドをオーバーライドする
- ステータスバーの状態を更新したい場合は UIViewController@setNeedsStatusBarAppearanceUpdate メソッドを呼び出す。(間接的にUIViewController@prefersStatusBarHidden が呼び出される。)
という上記の事はここでは取り上げません(笑)
ステータスバーに関する座標系の変更に加えて、やっかいだったのが以下のプロパティです。
- UIViewController.automaticallyAdjustsScrollViewInsets
このプロパティはiOS 7からのステータスバー分の座標の違いを吸収する為にUIScrollViewのInsetsを自動的に調整してくれるというプロパティです。
そしてデフォルトはYESです。
このプロパティのお陰で、独自にUIScrollViewのInsetsを設定している場合、画面回転等のタイミングで独自にInsetsを設定した後にステータスバー分の調整の為にInsetsを上書きしてくれます。
お陰で上手く動かない事があり、すぐに値をNOにして自動調整を止めました。
UIScrollViewとは言っても、UITableView、UITextView等もUIScrollViewを継承しているのでご注意を。
まとめ
上記内容は結構なレアケースですが、バグは兎も角、イベント発生タイミングや自動調整機能等のわかりにくい機能のせいで問題が出る事があるかと思います。
何かの役に立てば幸いです。