Search code examples
swiftmacosswiftuialert

Alert is shown only after I click away on something - Why?


OK, I'm not a SwiftUI expert. I am also not big on Swift. But I spent 20+ years coding in C and C++. So this "swift" UI thing is really puzzling. Can someone explain why this seemingly simple thing does not work.

Here's what I need to do: I have a macOS GUI app. When I click OK button in it I want to display a modal message box. Is it possible in Swift UI?

There's no function to do that, and one needs to use .alert for that.

So I did:

struct ContentView: View {
    
    @ObservedObject var gDVM = DataViewModel.shared
    
    var body: some View {
        
        NavigationView {

            MenuView(menuOptions: menuOptions,
                 curSelMenu: $currentMenu)
            
            ConfigView()

        }
        .alert(isPresented: $gDVM.gOKMsgBox.bShow) {
            //Show message box
            Alert(title: Text("Title"),
                  message: Text(gDVM.gOKMsgBox.strMsg)
            )
        }
   }
}

where:

class ModalOkMsgBoxInfo
{
    var bShow : Bool = false;
    var strMsg : String = ""
    
    func showOkMsgBox(msg : String)
    {
        strMsg = msg
        bShow = true
    }
}

class DataViewModel : ObservableObject
{
    static let shared = DataViewModel()
    
    @Published public var gOKMsgBox : ModalOkMsgBoxInfo
}

So when I want to display my message box:

struct ConfigView : View {
    
    @ObservedObject var gDVM = DataViewModel.shared
    
    var body : some View {

        //...

                Button(action: {
                    OK_proc()
                 }) {
                     Text("OK")
                 }
    }
}

func OK_proc() -> ()
{
    showOkMsgBox(msg: "Show a pop-up!")
}

func showOkMsgBox(msg : String)
{
    @ObservedObject var gDVM = DataViewModel.shared
    
    gDVM.gOKMsgBox.strMsg = msg
    gDVM.gOKMsgBox.bShow = true
}

First of all, why is it so complicated. But alright.

When I click my OK button and call my showOkMsgBox, nothing happens. And only when I click away into some other UI control, it shows my message box?

I spent an hour trying to figure it out.


Solution

  • The purpose of SwiftUI wrappers is to reload body they don’t belong inside functions because they don’t have a body.

    Also ModalOkMsgBoxInfo should be a struct not a class. Value/reference. Putting a reference type inside of a reference type is much harder to observe they must all be ObservableObjects and must be individually wrapped in a View

    Published emits changes when the “value” changes, changing a variable of a class doesn’t change the object’s value since the value is a way a memory reference. A struct is a value type so changing a variable is changing the value.