Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Catalyst Alert Showing Duplicate Buttons and Not Triggering Action

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
}
like image 594
TheNeil Avatar asked Dec 08 '19 01:12

TheNeil


Video Answer


2 Answers

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

like image 121
matteopuc Avatar answered Oct 12 '22 01:10

matteopuc


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.")
}
like image 25
Den Telezhkin Avatar answered Oct 12 '22 00:10

Den Telezhkin