Save Operation Timing Issue Not Display the Newest Entry

79 views Asked by At

I have a structure to display a list of bank / ATM withdrawal entries, and another structure to create a new entry for display in the list. When I press the save button after entering a new entry, operation is returning to the list structure and displaying all entries but the current entry before the method addNewWithdrawal() has had a chance to save the new entry (checked with a breakpoint).

So I have a timing issue occurring at the bottom of the saveButton() function--the question is how to fix it. It appears that I need to separate the two operations by placing things on separate threads and delaying the main thread until the save operation completes. But both threads are tied to views requiring the main thread.

Let me know if you would like to see the list view logic.

struct WdModel: Codable, Identifiable, Hashable {

    var id = UUID()
    var wdDate: Date        // bank withdrawal data
    var wdCode: String      
    var wdBank: String      
    var wdAmtL: Double      
    var wdAmtH: Double      
    var wdCity: String
    var wdState: String
    var wdCountry: String
}

class Withdrawal: ObservableObject {

@Published var wdArray: [WdModel] {
        didSet {
            // save withdrawal entries
            if let encoded = try? JSONEncoder().encode(wdArray) { // save withdrawal entries
                UserDefaults.standard.set(encoded, forKey: StorageKeys.wdBank.rawValue)
            }
        }
    }

init() {

        if let wdArray = UserDefaults.standard.data(forKey: StorageKeys.wdBank.rawValue) {    
            if let decoded = try? JSONDecoder().decode([WdModel].self, from: wdArray) {
                self.wdArray = decoded
                return
            }
        }
        self.wdArray = []

        if let encoded = try? JSONEncoder().encode(wdArray) {  
            UserDefaults.standard.set(encoded, forKey: StorageKeys.wdBank.rawValue)
        }
    }

 // save new withdrawal data
    func addNewWithdrawal(wdDate: Date, wdCode: String, wdBank: String, wdAmtL: Double, wdAmtH: Double, wdCity: String, wdState: String, wdCountry: String) {

        self.withdrawalTotal +=  wdAmtH

        let item = WdModel(wdDate: wdDate, wdCode: wdCode, wdBank: wdBank, wdAmtL: wdAmtL, wdAmtH: wdAmtH, wdCity: wdCity, wdState: wdState, wdCountry: wdCountry)
        self.wdArray.append(item)
}

Below is the code to save the newly created entry

// the save button has been pressed
    func saveButton() {
        // get coordinates and address
    
            // convert amount as string to double
            let moneyD = (wdAmtL as NSString).doubleValue

            let wdCode = currencies.curItem[userData.entryCur].curCode

            // get the local currency equivalent
            let rate = currencies.curItem[userData.entryCur].curRate

            // get local currency amount: use inverse rate
            wdAmtH = moneyD * (1 / rate)

**** Problem is occurring here when dismiss() and return to the list view happens before the data is saved (wdvm.addNewWithdrawal()


            // save entry to user defaults
            wdvm.addNewWithdrawal(wdDate: wdDate, wdCode: wdCode, wdBank: wdBank, wdAmtL: moneyD, wdAmtH: wdAmtH, wdCity: wdCity, wdState: wdState, wdCountry: wdCountry)
        }
        dismiss()
    }
struct WithdrawalView: View {

    @StateObject var wdvm = Withdrawal()

    var uniqueBankDates: [String] {
        Array(Set(wdvm.wdArray))                // This will remove duplicates, but WdModel needs to be Hashable
            .sorted { $0.wdDate < $1.wdDate }   // Compare dates
            .compactMap {
                $0.wdDate.formatted(date: .abbreviated, time: .omitted)    // Return an array of formatted the dates
            }
    }


    // filters entries for the given date
    func bankEntries(for date: String) -> [WdModel] {
        return wdvm.wdArray.filter { $0.wdDate.formatted(date: .abbreviated, time: .omitted) == date }
    }

    var body: some View {
        GeometryReader { g in

            VStack (alignment: .leading) {
                WDTitleView(g: g)
                List {
                    if wdvm.wdArray.isEmpty {

                        NoItemsView()

                    } else {

                        // outer ForEach with unique dates
                        ForEach(uniqueBankDates, id: \.self) { dateItem in  // change this to sort by date
                            Section {
                                // inner ForEach with items of this date
                                ForEach(bankEntries(for: dateItem)) { item in

                                    wdRow(g: g, item: item)

                                }
                            } header: {
                                Text("\(dateItem)")
                            }
                        }.onDelete(perform: deleteItem)
                    }
                }
                .navigationBarTitle("Bank Withdrawals", displayMode: .inline)
                .environment(\.defaultMinListRowHeight, g.size.height > g.size.width ? 9 : 5)
                .navigationBarItems(trailing: NavigationLink (destination: AddWithdrawalView()) {
                    Image(systemName: "plus")
                        .resizable()
                        .frame(width: 18, height: 18)
                })
            }
        }
        if !wdvm.wdArray.isEmpty {
            ShowWdTotal()
        }
    }

    // may delete entries with swipe left
    func deleteItem(at offsets: IndexSet) {
        var money: Double = 0

        offsets.forEach { singleOffset in

            money = wdvm.wdArray[singleOffset].wdAmtH
            wdvm.withdrawalTotal -= money
            wdvm.wdArray.remove(atOffsets: offsets)
        }
    }
}
0

There are 0 answers