Ataman
Ataman

Reputation: 2590

UserDefault value does not update in a list SwiftUI

I have two views, embedded in TabView. I am using userdefaults in a class called usersettings.

class UserSettings: ObservableObject {
    @Published var favList: [String] {
        willSet {
            print("willset")
        }
        didSet {
            UserDefaults.standard.set(favList, forKey: "isAccountPrivate")
            print("didset")
        }
    }
    init() {
        self.favList = UserDefaults.standard.object(forKey: "isAccountPrivate") as? [String] ?? ["Sepetiniz Boş"]
    }
}

In Button View, which acts like add/remove favorite. It successfully adds and remove from the UserDefaults. But when I add something it does not show on the other view (please see the next code after FavButton)

struct FavButton: View {
    
    @Binding var passedFood: String
    @ObservedObject var userSettings = UserSettings()

    var body: some View {

        Button(action: {
            if userSettings.favList.contains(passedFood) {
                userSettings.favList.remove(at: userSettings.favList.firstIndex(of: passedFood )!)
            } else {
                
                userSettings.favList.append(passedFood)
                
            }
            
        })  
        
    }
}

But it does not update my list in this other view unless I close and open my app. If I remove something from the list, it actually removes from the userdefault.

If I add a new word within this view, it works too.

My only problem is when I add something from another view (FavButton) it does not show in this view (FavView).

struct FavView: View {
    
    @ObservedObject var userSettings = UserSettings()
    @State private var newWord = ""

    var body: some View {
        
        NavigationView {
            List {
                TextField("Ürün Ekleyin...", text: $newWord, onCommit: addNewWord)
                ForEach( self.userSettings.favList, id: \.self) { list in
                    Text(list)
                        .font(.headline)
                        .padding()
                    
                }
                .onDelete(perform: self.deleteRow)
            }
            .navigationTitle("Sepetim")
        }
    }
    
    private func deleteRow(at indexSet: IndexSet) {
        
        self.userSettings.favList.remove(atOffsets: indexSet)
    }
    
    private func addNewWord() {
        let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
        self.userSettings.favList.append(answer)
        guard answer.count > 0 else {
            return
        }
        newWord = ""
    }
    
}

Upvotes: 1

Views: 605

Answers (2)

magnuskahr
magnuskahr

Reputation: 1330

A better approach to follow the SwiftUI idiom is to use the .environmentObject() modifier.

When you declare your app:

struct AppScene: App {

  @StateObject private var userSettings = UserSettings() // Use state object to persist the object

  var body: some Scene {
    WindowGroup {
      ContentView()
        .environmentObject(userSettings) // Inject userSettings into the environment 
    }
  }
}

and then in you ContentView you can reach into your environment and get the object:

struct ContentView: View {
  @EnvironmentObject private var userSettings: UserSettings
  var body: some View {
    Text("Number of items in favList: \(userSettings.favList.count)")
  }
}

Upvotes: 2

Asperi
Asperi

Reputation: 258541

You need to use same instance of UserSettings in all views where you want to have observed user settings, like

class UserSettings: ObservableObject {
   static let global = UserSettings()
//... other code
}

and now

struct FavButton: View {
    @ObservedObject var userSettings = UserSettings.global    // << here !!

// ... other code
}

and

struct FavView: View {
    @ObservedObject var userSettings = UserSettings.global   // << here !!

// ... other code
}

Upvotes: 0

Related Questions