一昨日くらいにiOS 8でテストをしていたら見つけました。
問題となる画面構成を多用するアプリケーションにとっては、修正が間に合わなければけっこう致命的と思われるので共有します。
(Base SDKをiOS 8にしてビルドしない限りは起こりません。リリース済みのアプリケーションをiOS 8で動かすぶんには問題無いです。)
↓ バグレポートした内容は下記の記事で公開しています。
重ねてレポートすると優先順位があがるかもしれません。
サンプルコード
↓ バグレポートに添付した問題が再現するサンプルコードです。
Xcode 6でビルドして、iOS 8のiPadで実行すると問題が再現できます。
事象について
事象を簡単にまとめると、モーダルビューの上にポップオーバーを表示している時、暗いところをタップしたらポップオーバーが消える、のが通常だけど、それを2回以上タップすると、下のモーダルビューまで閉じてしまう。
調べると、下のビューのdismissViewController〜メソッドが呼ばれることでポップオーバーが閉じるのだけど、
ダブルタップ以上すると、それが複数回呼ばれるので、ポップオーバー以外のビューも閉じられてしまう、という理屈です。
具体的な影響
このダブルタップの間隔は暗くなっているビューのalphaがゼロになるまでにすれば再現するので、かなりゆっくりでも起こってしまいます。
ちょっと反応が悪いかな?と思ってもう一回タップすると画面全体が消えてしまった、みたいなことが普通に起こります。
やっかいな点は、ポップオーバー形式で表示するビューは何でもこの問題の対象となることです。
iPadでは自動的にポップオーバーで表示されてしまうものや、ポップオーバーで表示しなければならない標準のビューはけっこうあって、UIActionSheetやUIImagePickerController、共有につかうUIActivityViewController、UIDocumentInteractionControllerなどが全部対象になります。
↓ 例えば、下のような画面でモーダルビューでUIWebViewを表示して、そこに共有のためのボタンがある、みたいな画面も対象になります。
(下の状態で暗いところをダブルタップすると、UIWebViewを表示しているモーダルビューも閉じてしまう)
救いなのは、Xcode 6つまりBase SDKをiOS 8にしてビルドしない限りはこの問題は起こらないことです。
(リリース済みのアプリケーションをiOS 8で使うぶんには問題ない)
ただ、満を持してiOS 8のリリースと同時にアップデートしたアプリケーションで問題が起きたらいろいろ大変だと思うので、iPad対応アプリケーションを出してるひとは気をつけてください。
対策
もし、GMで修正されていなかったときのためにいちおう対策を考えました。
標準のUIActionSheetとかで起こるので、呼び出し側で工夫するのは限界があるので、問題の起こっている、暗いところをタップしたときのイベントハンドラをSwizzlingして同じインスタンスの呼び出しなら1度しか実行しない、というようにしてみました。
正直、こういうコードをプロダクトに入れたくはないので、修正が間に合うことを願っています。
static IMP __Original_UIPopoverPresentationController_dimmingViewWasTapped; void __Swizzle_UIPopoverPresentationController_dimmingViewWasTapped(id self, SEL _cmd, id sender) { static id dimmingView; if (dimmingView == sender) { return; } dimmingView = sender; __Original_UIPopoverPresentationController_dimmingViewWasTapped(self, _cmd, sender); } + (void)load { Class clazz = NSClassFromString(@"UIPopoverPresentationController"); SEL selector = @selector(dimmingViewWasTapped:); Method method = class_getInstanceMethod(clazz, selector); __Original_UIPopoverPresentationController_dimmingViewWasTapped = method_setImplementation(method, (IMP)__Swizzle_UIPopoverPresentationController_dimmingViewWasTapped); }