WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Trouble loading array saved in user defaults

Forums > SwiftUI

I have been banging my head trying to get this basic bill tracking app project I started to persist data.

I think it will now save the struct/array "entries" to userdefaults, but I cannot for the life of me figure out how to load the data back into the array (entries) that holds the values (and is looped through to display entered bills and amounts).

here is the code so far:

import SwiftUI

struct ContentView: View {
    //test codable added
    struct BillEntry : Identifiable, Codable {
        let id = UUID()
        var billName : String
        var billAmount : Double
    }

    @State var bill : String = ""
    @State var amount : Double = 0.00
    @State var amountTxt: String = ""
    @State var entries = [BillEntry]()

    var body: some View {
        NavigationView {
            Form{
                Section(header:Text ("BILL ENTRY")) {
                    TextField ("Bill Name / Deposit Name", text: $bill)
                    TextField("Amount", text: $amountTxt)
                        .onChange(of: amountTxt) { _ in                          //2
                            amount = Double(amountTxt) ?? 0.0
                    }
                }
            Section {
                Button(action: {
                    entries.append(
                        BillEntry(billName: bill, billAmount: amount))
                        UserDefaults.standard.set(try? PropertyListEncoder().encode(entries), forKey: "Bills")
                        //UserDefaults.standard.set(self.entries, forKey: "Bills")
                }) {
                    Text("Add Bill")
                        .foregroundColor(Color.primary)
                    }
                }                
                Section(header: Text("Current Bills")) {
                    List{
                        ForEach(entries) {
                            entry in Text("\(entry.billName): \(entry.billAmount, specifier: "%.2f")")
                        }
                    }
                }
            }
            .navigationBarTitle("Bills")
        }
    }
}

Any help on how to load the data saved to defaults back into 'entries' when the app launches is greatly appreciated, been stuck on this for weeks.

1      

hi,

one modification to the BillEntry struct would help:

    struct BillEntry : Identifiable, Codable {
        let id: UUID    // do not set; otherwise, you cannot decode it from a property list
        var billName : String
        var billAmount : Double

        // custom init, passes in name and amount & creates the id
        init(billName: String, billAmount: Double) {
            id = UUID()
            self.billName = billName
            self.billAmount = billAmount
        }
    }

and then all you need to do is add an .onAppear modifier to the Form:

.onAppear {
    if let encodedData = UserDefaults.standard.data(forKey: "Bills") {
        do {
            entries = try PropertyListDecoder().decode([BillEntry].self, from: encodedData)
        } catch let error as NSError {
            NSLog("Unable to decode: error = \(error.localizedDescription)")
        }
    }
}

that should be about the right thing (quick test looks good). hope that helps,

DMG

2      

Thank you! That got it working, and I was finally able to work on other stuff to get the skeleton working.

1      

Do note, though, that this really isn't the kind of thing you should be storing in UserDefaults.

UserDefaults is for storing small amounts of frequently-read, infrequently-written data, like settings. Having a button that the user can press to generate more data is pretty much not that.

1      

@roosterboy,

I appreciate that input too, this is my personal challenge project I made for myself that starts simple enough I could get a base skeleton working (albeit not yet persisting data in the /proper/ way). I plan to keep going back and rebuilding newer/better versions as I learn more, and if/when I get a grasp on core data I plan to rebuild it using that.

For now its techically working, so I am learning more with the 100 days of SwiftUI material here (just finished day 19) so I can learn more and build it better in a future iteration.

Cheers!

1      

Hacking with Swift is sponsored by Fernando Olivares

SPONSORED Fernando's book will guide you in fixing bugs in three real, open-source, downloadable apps from the App Store. Learn applied programming fundamentals by refactoring real code from published apps. Hacking with Swift readers get a $10 discount!

Read the book

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.