Home > Enterprise >  How to Update specific value in UserDefault
How to Update specific value in UserDefault

Time:09-26

I have the below code that saves my array to UserDefaults at app startup and loads the data correctly, I use the propertyObserver didSet, hoping that any time a value is reset in value type struct , this will create a change in the @Published array of this type, so far so good, fast forward,

Now I need a way to add favourites , I do so by using a @Binding of a that specific song passed from the album View, I toggle it and it works, but only as long I do not relaunch the app, how can I make this change permanent , like in CoreData, I do not know how I can specifically change UserDefault value, thanks

Where I use UserDefaults to save the array

struct Song: Identifiable, Codable {
    var id = UUID()
    var name: String
    var album: String
    var isFavorite: Bool
    var genre: String
    var artist: String
    init(name: String, album: String, isFavorite: Bool, genre: String, artist: String) {
        self.name = name
        self.album = album
        self.artist = artist
        self.genre = genre
        self.isFavorite = isFavorite
    }
    static let `default` = Song(name: "demo", album: "demo", isFavorite: false, genre: "demo", artist: "demo")
   
}

class Songs: ObservableObject {
    var songsData: [Song] =
            [
                Song(name: "demo", album: "demo", isFavorite: false, genre: "demo", artist: "demo"),
                Song(name: "demo", album: "demo", isFavorite: false, genre: "demo", artist: "demo"),
                Song(name: "demo", album: "demo", isFavorite: false, genre: "demo", artist: "demo"),
                Song(name: "demo", album: "demo", isFavorite: false, genre: "demo", artist: "demo"),
                Song(name: "demo", album: "demo", isFavorite: false, genre: "demo", artist: "demo"),
            ]

    @Published var songs = [Song]() {
        didSet {
            if let encoded = try? JSONEncoder().encode(songsData) {
                UserDefaults.standard.set(encoded, forKey: "demosongs")
            }
        }
    }
    
   
    
   
    
   
    init(){
        if let savedItems = UserDefaults.standard.data(forKey: "demosongs") {
               if let decodedItems = try? JSONDecoder().decode([Song].self, from: savedItems) {
                   songs = decodedItems
                   return
               }
           }
           songs = []
       }
}

Where I try to set the song as favourite but this change is not permanent , how can I make it permanent by making changes to UserDefaults for the specific record

struct SongView: View {
    @Binding var song: Song
   
    var body: some View {
        Text("\(song.name)")
       
        Button(song.isFavorite ? "Remove from favorite" : "add to favorites") {
            song.isFavorite.toggle()
        }
        Text("Hello World")
    }
}

// Edit for vadian

I have the album view if I use songs instead of songs data , this view is then empty

struct AlbumView: View {
    @ObservedObject var songData: Songs
    var body: some View {
        
        ZStack {
            Image("cover")
                .resizable().opacity(0.5)
                .zIndex(1)
       
            ScrollView {
                VStack {
                    ForEach($songData.songs) { $song in
                        NavigationLink {
                            SongView(song: $song, songs: Songs())
                            
                        } label: {
                            customText(image: "joinus", str: song.name)
                                .frame(maxWidth: .infinity)
                        }
                    }
                }.padding()
            }.zIndex(2)
        }
        
    }
    
    func customText(image: String, str: String) ->  some View {
        Group {
            VStack {
                RoundedRectangle(cornerRadius: 20)
                    .fill(.blue)
                    .padding()
                    .frame(width: 300, height: 150)
                    .overlay(Image(image)
                        .resizable()
                        .frame(width: 300, height: 150))
                Text(str)
                    .scaledFont(name: "Gothic", size: 20)
                    .foregroundColor(.white)
                    .padding()
                    .background(RoundedRectangle(cornerRadius: 20, style: .continuous).fill(Color.gray))
            }
        }
    }
}

CodePudding user response:

You save always the (unmodified) songsData array. It must be

if let encoded = try? JSONEncoder().encode(songs) { ...

And you have to change the init method to assign the default array if nothing is saved yet in UserDefaults

init(){
    if let savedItems = UserDefaults.standard.data(forKey: "demosongs"),
       let decodedItems = try? JSONDecoder().decode([Song].self, from: savedItems) {
        songs = decodedItems
    } else {
        songs = songsData
    }
}
  • Related