🚨

iOS15でSwiftUIのAlertを連続で定義できない問題が解決していた

2022/10/03に公開2

概要

iOS16が出ましたね。経験上、多くの企業は大体最新のOSバージョンから2バージョンまでをサポートする傾向にあると思うのでそろそろiOS15以降をターゲットにしたアプリも増えてくる頃だと思います。
SwiftUIでは下のように同じViewに連続して .alert Modifierをつけると片方のアラートが表示されないというバグが存在していました。しかし、この記事の結論でもありますが、iOS15以降から使える .alert 系のModifierを使うとこのバグを回避できます。iOS15以降のサポートになったらそれらを使っていきましょう。

alert(isPresented:content:)

struct ContentView: View {
    @State private var isPresented1 = false
    @State private var isPresented2 = false

    var body: some View {
        VStack(spacing: 20) {
            Button {
                isPresented1 = true
            } label: {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                Text("Button 1")
            }

            Button {
                isPresented2 = true
            } label: {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                Text("Button 2")
            }
        }
        .padding()
        .alert(isPresented: $isPresented1) {
            Alert(title: Text("Alert 1"))
        }
        .alert(isPresented: $isPresented2) {
            Alert(title: Text("Alert 2"))
        }
    }
}

私の環境では後半の Alert 2 は表示されますが Alert 1 は表示されない動きになります。この記事には書きませんがこれには色々なワークアラウンドがありました。ただ、先ほど使っていた .alert Modifierはdeprecatedになっており、iOS15以降では違うAPIが用意されています。例えばこれ。この他にもerrorに特化したものなどalertのModifierなどModifierの種類自体も増えalert周辺の機能が充実しました

そして、iOS15以降からサポートされている .alert Modifierではどうやら前述した連続して .alert Modifierをつけると片方のアラートが表示されないというバグは修正済みのようです。先ほどのコードを新しいAPIで書き直した一例が下記のようになります。 Alert 1Alert 2 も表示できることが確認できます。

struct ContentView: View {
    @State private var isPresented1 = false
    @State private var isPresented2 = false

    var body: some View {
        VStack(spacing: 20) {
            Button {
                isPresented1 = true
            } label: {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                Text("Button 1")
            }

            Button {
                isPresented2 = true
            } label: {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
                Text("Button 2")
            }
        }
        .padding()
        .alert("Alert 1", isPresented: $isPresented1, actions: {
            Button("OK", action: { })
        })
        .alert("Alert 2", isPresented: $isPresented2, actions: {
            Button("OK", action: { })
        })
    }
}

まとめ

iOS15以降がターゲットになったら新しい .alert に置き換えましょう

おしまい \(^o^)/

Discussion

acevifacevif

助かりました。
deprecatedなAPIのほうでは相変わらず同じバグがあるんですね。

bannzaibannzai

ですね。iOS14から残っているalertの方ではバグがOSに関わらず残っています