简体   繁体   中英

SwiftUI manipulate items from a struct from a view

I'd like the ability to edit and put into a new view the 'expenses' the user adds. I've been having problems accessing the data after a new expense has been added. I am able to delete the items and add them up but I'd like to click on the 'expenses' and see and edit the content in them Image of the view

//Content View

import SwiftUI

struct ExpenseItem: Identifiable, Codable {
    let id = UUID()
    let name: String
    let type: String
    let amount: Int
}

class Expenses: ObservableObject {
@Published var items = [ExpenseItem]() {
    didSet {
        let encoder = JSONEncoder()
        
        if let encoded = try?
            encoder.encode(items) {
            UserDefaults.standard.set(encoded, forKey: "Items")
        }
    }
}

init() {
    if let items = UserDefaults.standard.data(forKey: "Items") {
        let decoder = JSONDecoder()
        
        if let decoded = try?
            decoder.decode([ExpenseItem].self, from: items) {
            self.items = decoded
            return
        }
    }
}

// Computed property that calculates the total amount
var total: Int {
    self.items.reduce(0) { result, item -> Int in
        result + item.amount
    }
}
}

struct ContentView: View {
@ObservedObject var expenses = Expenses()
@State private var showingAddExpense = false

var body: some View {
    NavigationView {
        List {
            ForEach(expenses.items) { item in
                HStack {
                    VStack {
                        Text(item.name)
                            .font(.headline)
                        Text(item.type)
                    }
                    
                    Spacer()
                    Text("$\(item.amount)")
                }
            }
            .onDelete(perform: removeItems)
            
            // View that shows the total amount of the expenses
            HStack {
                Text("Total")
                Spacer()
                Text("\(expenses.total)")
            }
        }
        .navigationBarTitle("iExpense")
        .navigationBarItems(trailing: Button(action: {
            self.showingAddExpense = true
        }) {
            Image(systemName: "plus")
            }
        )
        .sheet(isPresented: $showingAddExpense) {
            AddView(expenses: self.expenses)
        }
    }
}

func removeItems(at offsets: IndexSet) {
    expenses.items.remove(atOffsets: offsets)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

//AddExpense

import SwiftUI

struct AddView: View {
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var expenses: Expenses
    @State private var name = ""
    @State private var type = "Personal"
    @State private var amount = ""
    static let types = ["Business", "Personal"]

var body: some View {
    NavigationView {
        Form {
            TextField("Name", text: $name)
            
            Picker("Type", selection: $type) {
                ForEach(Self.types, id: \.self) {
                    Text($0)
                }
            }
            
            TextField("Amount", text: $amount)
                .keyboardType(.numberPad)
        }
        .navigationBarTitle("Add new expense")
        .navigationBarItems(trailing: Button("Save") {
            if let actualAmount = Int(self.amount) {
                let item = ExpenseItem(name: self.name, type: self.type, amount: actualAmount)
                self.expenses.items.append(item)
                self.presentationMode
                    .wrappedValue.dismiss()
            }
        })
    }
}
}

struct AddView_Previews: PreviewProvider {
    static var previews: some View {
        AddView(expenses: Expenses())
    }
}

Remove @observedObject in AddView.

A view cannot change an ObservableObject. ObservableObject is used for being notified when a value is changed. When you pass the expenses class to AddView, you are giving it a reference. Therefore, AddView can change the expenses, and consequently update ContentView.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM