7

For some reason, the following code is displaying an Alert with three instances of the same button, none of which trigger the action (just a simple console output for an example) as expected:

Duplicate Buttons in Alert

Has anyone else experienced this? Any suggestions on a fix?

It's building on Xcode 11.2.1, for an iOS 13.0 target, then running on macOS (10.15.1) via Catalyst.

Update 1: This appears to be an issue specific to Catalyst. When the same code is run on an iPhone simulator, it shows one button and executes the action, as expected.

Update 2: The issue also wasn't fixed by updating to Xcode 11.3.1 and macOS 10.15.3.

public struct ContactUsView: View {
    
    @ObservedObject private var contactUsVM: ContactUsViewModel
    
    private var successAlert: Alert {
        Alert(
            title: Text("Email Sent"),
            message: Text("Thanks for taking the time to reach out to us. We appreciate it!"),
            dismissButton: .default(Text("OK")) {
                self.dismissSelf()
            }
        )
    }
    
    public var body: some View {
        Form {
            // ...
        }
        .alert(isPresented: self.$contactUsVM.contactAttemptSucceeded) {
            self.successAlert
        }
    }

    public init() {
        self.contactUsVM = ContactUsViewModel()
    }
    
    private func dismissSelf() {
        print("Dismissing!")
    }
}

class ContactUsViewModel: ObservableObject {

    @Published var contactAttemptSucceeded: Bool = true
}
TheNeil
  • 3,321
  • 2
  • 27
  • 52

3 Answers3

1

It seems that your code works fine on xCode 11.5 MacOs 0.15.4. If you run your example (I've just filled the hole in your code):

import SwiftUI

public struct ContactUsView: View {

    @ObservedObject private var contactUsVM: ContactUsViewModel

    private var successAlert: Alert {
        Alert(
            title: Text("Email Sent"),
            message: Text("Thanks for taking the time to reach out to us. We appreciate it!"),
            dismissButton: .default(Text("OK")) {
                self.dismissSelf()
            }
        )
    }

    public var body: some View {
        Form {
            Text("Hello World")
        }
        .alert(isPresented: self.$contactUsVM.contactAttemptSucceeded) {
            self.successAlert
        }
    }

    public init() {
        self.contactUsVM = ContactUsViewModel()
    }

    private func dismissSelf() {
        print("Dismissing!")
    }
}

class ContactUsViewModel: ObservableObject {

    @Published var contactAttemptSucceeded: Bool = true
}

You'll see this:

enter image description here

superpuccio
  • 11,674
  • 8
  • 65
  • 93
1

This seems to be fixed on macOS Big Sur. Unfortunately, for those folks, who need to support macOS Catalina(me included), the only workaround is to create alert using UIAlertController.

The way I did that, is dispatching notification to SceneDelegate instance, and presenting UIAlertController on UIHostingController:

NotificationCenter.default.addObserver(forName: .showMailUnavailableAlert, object: nil, queue: nil) { [weak self] _ in
    let controller = UIAlertController(title: "Default email client is not configured.", preferredStyle: .alert)
    controller.addAction(.init(title: "Ok", style: .cancel, handler: nil))
    self?.window?.rootViewController?.present(controller, animated: true, completion: nil)
}

extension NSNotification.Name {
    static let showMailUnavailableAlert = NSNotification.Name("Email not configured.")
}
Den Telezhkin
  • 633
  • 6
  • 9
0

I don't know how to fix the duplicate buttons but to get the alert to dismiss you might need to add this line under the ObservedObject line:

@Environment(\.presentationMode) var presentationMode

and then add this:

presentationMode.wrappedValue.dismiss()

to your dismissSelf() func.

This is what I gleaned from a Hacking Swift video by Paul Hudson.

WholeCheese
  • 437
  • 3
  • 14
  • Thanks, but that part I know. The point is that the method isn’t getting called even to do the log output. The functionality itself is only a secondary consideration to the broken alerts. – TheNeil Dec 03 '20 at 15:51