カテゴリー: iOS

[Swift]iPadのActionSheet表示でクラッシュする問題

はじめに

こんにちは、nukkyです。
私は普段iPhoneアプリの開発を主に行っているのですが
慣れか油断かiPadでの確認をおろそかにしてしまい、
クラッシュバグの存在に長い間気づかないでいたので
戒めつつ備忘録としてここに残したいと思います。

エラー内容

エラー原因

まずはサンプルコード
ボタンをタップしたらUIAlertControllerで
ActionSheetを表示するサンプルです。

@IBAction func showAlert(_ sender: Any) {
    let actionSheet = UIAlertController(title: "タイトル", message: "メッセージ", preferredStyle: UIAlertControllerStyle.actionSheet)
    
    let action1 = UIAlertAction(title: "アクション1", style: UIAlertActionStyle.default, handler: {
        (action: UIAlertAction!) in
    })
    
    let action2 = UIAlertAction(title: "アクション2", style: UIAlertActionStyle.default, handler: {
        (action: UIAlertAction!) in
    })
    
    let action3 = UIAlertAction(title: "アクション3", style: UIAlertActionStyle.destructive, handler: {
        (action: UIAlertAction!) in
    })
    
    let cancel = UIAlertAction(title: "キャンセル", style: UIAlertActionStyle.cancel, handler: {
        (action: UIAlertAction!) in
    })
    
    actionSheet.addAction(action1)
    actionSheet.addAction(action2)
    actionSheet.addAction(action3)
    actionSheet.addAction(cancel)
    self.present(actionSheet, animated: true, completion: nil)
}

このソースを実行するとiPhoneでは問題なく表示されますが
iPadで実行すると以下のクラッシュ発生してしまいます。。。

Terminating app due to uncaught exception 'NSGenericException', reason: 
'Your application has presented a UIAlertController (<UIAlertController: 0x7f80fb418ae0>) of 
style UIAlertControllerStyleActionSheet. The modalPresentationStyle of a UIAlertController 
with this style is UIModalPresentationPopover. You must provide location information for 
this popover through the alert controller's popoverPresentationController. You must provide 
either a sourceView and sourceRect or a barButtonItem.  If this information 
is not known when you present the alert controller, you may provide it in the 
UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'

結論を述べると、

UIAlertControllerでActionSheetを表示する際に
popoverPresentationControllerの
sourceViewを指定しないとクラッシュします!!!

というわけで上記ソースを少し修正。

actionSheet.addAction(action1)
actionSheet.addAction(action2)
actionSheet.addAction(action3)
actionSheet.addAction(cancel)
// iPadでは必須!
actionSheet.popoverPresentationController?.sourceView = self.view

self.present(actionSheet, animated: true, completion: nil)

この一文を加えることでクラッシュを回避できます。

まだこれで解決ではない

上記の対応によりクラッシュは回避できましたが、
このままiPadで実行すると以下の様な表示になります。

このままだと不恰好なので、
ActionSheetの表示位置を調整します。

actionSheet.popoverPresentationController?.sourceView = self.view
let screenSize = UIScreen.main.bounds
// ここで表示位置を調整
// xは画面中央、yは画面下部になる様に指定
actionSheet.popoverPresentationController?.sourceRect = CGRect(x: screenSize.size.width/2, y: screenSize.size.height, width: 0, height: 0)

self.present(actionSheet, animated: true, completion: nil)

これを実行すると以下の様な表示になります。

ちなみに、popoverPresentationControllerの
sourceRectですが、iPhoneで表示する際には全く影響がないので
iPad用に処理を分ける必要はないです。

 

さいごに

確認すれば、すぐに発生する不具合に
長いこと気づかず、本当に恥ずかしかったです、、、
今回に限った話ではないですが何事も確認というものは改めて大事だと思いました。
そういう思いで書いた、この記事が誰かのお役にたてれば嬉しいです。

nukky

コメントを見る

シェア
執筆者:
nukky
タグ: Swift

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前