[SOLVED] Published Bool variable resetting automatically

Issue

I have the following simple SwiftUI view which contains a component containing a list of marketing preference options with checkboxes and a button to update the preferences:

@StateObject var marketingPreferencesViewModel: MarketingPreferencesViewModel

var body: some View {
    VStack {
        MarketingPreferencesView(viewModel: .init())
        Button {
            marketingPreferencesViewModel.marketingUpdateRequested()
        } label: {
            Text("Update prefs")
        }
    }
}

MarketingPreferencesView is as follows:

struct MarketingPreferencesView: View {

@ObservedObject var viewModel: MarketingPreferencesViewModel

var body: some View {
    VStack(alignment: .leading) {
        marketingPreference(type: .email)
        marketingPreference(type: .directMail)
        marketingPreference(type: .notification)
        marketingPreference(type: .sms)
        marketingPreference(type: .telephone)
    }
}

func marketingPreference(type: MarketingOptions) -> some View {
    HStack {
        if viewModel.preferencesAreLoading {
            ProgressView()
        } else {
            Button {
                switch type {
                case .email:
                    viewModel.emailMarketingEnabled.toggle()
                case .notification:
                    viewModel.notificationMarketingEnabled.toggle()
                case .sms:
                    viewModel.smsMarketingEnabled.toggle()
                case .telephone:
                    viewModel.telephoneMarketingEnabled.toggle()
                case .directMail:
                    viewModel.directMailMarketingEnabled.toggle()
                }
                
            } label: {
                switch type {
                case .email:
                    viewModel.emailMarketingEnabled ? Image.General.Checkbox.checked : Image.General.Checkbox.unChecked
                // ... remaining switch cases follow same pattern
                }
            }
        }
        Text(type.title())
    }
    .padding(.bottom, Constants.bottomPadding)
}

}

And the MarketingPreferencesViewModel:

 class MarketingPreferencesViewModel: ObservableObject {
    @Published var emailMarketingEnabled = false {
        didSet {
            print(emailMarketingEnabled)
        }
    }
    @Published var directMailMarketingEnabled = false
    @Published var notificationMarketingEnabled = false
    @Published var smsMarketingEnabled = false
    @Published var telephoneMarketingEnabled = false
    
    private func updateMarketingPreferences() {
        // For now, just printing emailMarketingEnabled value for debugging
        print(emailMarketingEnabled)
    }
    
    func marketingUpdateRequested() {
         self.updateMarketingPreferences()
       }  
    }
}

So the user taps on the marketing preference button, this toggles the corresponding value in the view model.

However, for some reason when I hit the marketingUpdateRequested() method, if I check the value of emailMarketingEnabled, it is always false even if I have toggled it already.

Steps to reproduce:

  • Tap on the emailMarketingEnabled button
  • ‘true’ is printed in the console
  • tap on the ‘Update prefs’ button
  • ‘false’ is printed

I have placed the didSet on the emailMarketingEnabled property to see if it changes elsewhere, and it does not. Why then, once I have set to true, is this then false when I tap the button?

Solution

You need to instantiate the MarketingPreferencesViewModel, then pass it to your
MarketingPreferencesView, like in the following example code:

// -- here
@StateObject var marketingPreferencesViewModel = MarketingPreferencesViewModel()  

var body: some View {
    VStack {
        MarketingPreferencesView(viewModel: marketingPreferencesViewModel)  // <-- here
        Button {
            marketingPreferencesViewModel.marketingUpdateRequested()
        } label: {
            Text("Update prefs")
        }
    }
}

Answered By – workingdog support Ukraine

Answer Checked By – Candace Johnson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.