kyrers
kyrers

Reputation: 539

Cannot get UserDefautls updated values in realtime

I'm new to swift and I cannot get the UserDefaults updated values in the same session. Only after the application restarts.

Here is what I mean in some code:

//This is where I have the userdefaults
@ObservedObject var userSettingsController = UserSettingsController

//These are the auxiliar vars I created to help me achieve the conditional renders I need. I'm looking to get rid of these and use the usersettings updated values
@State private var showMap = false
@State private var showTutorial = true

//Partial code of my view, where I'm using the variables
if(!self.userSettingsController.showActionSheet && self.showMap) {
   showMapView()
     .onTapGesture {
        if (self.userSettingsController.showNextDeparturesTutorial && self.showTutorial {
          self.showTutorial = false
          self.userSettingsController.showNextDeparturesTutorial.toggle()
        } else {
        //code that has nothing to do with the question

No, here is my UserSettings and UserSettingsController classes:

UserSettings

import Foundation

struct UserSettings {
    var settings: UserDefaults

    init() {
        self.settings = UserDefaults.standard
        self.settings.register(
            defaults: [
                "userCity": "",
                "showUserCityActionSheet": true,
                "showNextDeparturesTutorial": true,
        ])
    }
}

UserSettingsController

import Foundation
import Combine
import SwiftUI

class UserSettingsController: ObservableObject {
    @Published var userSettings = UserSettings()

    var userCity : String {
        get {
            return self.userSettings.settings.string(forKey: "userCity") ?? ""
        }
        set {
            self.userSettings.settings.set(newValue, forKey: "userCity")
        }
    }

    var showUserCityActionSheet: Bool {
        get {
            return self.userSettings.settings.bool(forKey: "showUserCityActionSheet")
        }
        set {
            self.userSettings.settings.set(newValue, forKey: "showUserCityActionSheet")
        }
    }

    var showNextDeparturesTutorial: Bool {
        get {
            return self.userSettings.settings.bool(forKey: "showNextDeparturesTutorial")
        }
        set {
            self.userSettings.settings.set(newValue, forKey: "showNextDeparturesTutorial")
        }
    }
}

My question is, how can I get the updated values of the UserDefault values showNextDeparturesTutorial and showActionSheet in realtime? I've already tried to store them in other variables but to no avail.

Thanks.

EDIT

I accepted @Asperi answer because it was the most efficient one considering my project. However, @pawello2222 answer would also solve my problem.

Thanks, all.

Upvotes: 1

Views: 610

Answers (3)

Asperi
Asperi

Reputation: 257563

The possible solution is to activate ObservableObject publisher explicitly in every setter, like below

var userCity : String {
    get {
        return self.userSettings.settings.string(forKey: "userCity") ?? ""
    }
    set {
        self.userSettings.settings.set(newValue, forKey: "userCity")
        self.objectWillChange.send()   // << this one !!
    }
}

Upvotes: 3

pawello2222
pawello2222

Reputation: 54436

You can make your variables @Published. This way their changes will be detected by your View.

Every time you modify some of these variables it will be saved to UserDefaults as well. And when you init your UserSettingsController you have to load values from UserDefaults first:

class UserSettingsController: ObservableObject {
    private let userSettings = UserDefaults.standard

    @Published var showNextDeparturesTutorial: Bool {
        didSet {
            self.userSettings.set(showNextDeparturesTutorial, forKey: "showNextDeparturesTutorial")
        }
    }

    init() {
        _showNextDeparturesTutorial = .init(initialValue: userSettings.bool(forKey: "showNextDeparturesTutorial"))
    }
}
struct ContentView: View {
    @ObservedObject var userSettingsController = UserSettingsController()
    ...
}

Upvotes: 2

woneill1701
woneill1701

Reputation: 331

The problem is not the UserDefaults, it is that SwiftUI is not detecting any changes in the data since your data resides in the UserDefaults database and SwiftUI can’t see the changes.

The @Published on the userSettings variable is no use here since it is an object, and in the current version of SwiftUI/Combine, it only detects changes of the object being referenced, instead of changes within the object. E.g. if you assigned a different defaults object to UserDefaults it would fire its ObjectWillChange publisher.

You would be better off storing your settings values in actual variables, and using didSet to persist them to the User Defaults Database on each change. You would then only need to load them on startup to get the data back from User Defaults.

Upvotes: 1

Related Questions