UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: iExpense: How do I calculate total expenses as a computed property?

Forums > 100 Days of SwiftUI

I'd like to calculate and display the total expenses that the user inputs into the app. I think a computed property called totalExpense within the contentView is the right approach, but I'm stuck on how to do this calculation.

Below is some preliminary background. If this is not enough info, I'll share my github repository at the end of the message.

Background Within the iExpense project, I have a struct, which defines each expense item:

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

Then I have a class, which is an array of expenseItems

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

I'm thinking of creating a computed property within my contentView, but this is where I get stuck.

  @State private var totalExpenses: Double {
  // perform calculation for total expenses using class??
  }

Appreciate any help on this!

Github repo: (see lines 14 and 26 in ContentView): https://github.com/iosPit/ExpenseTracker

2      

Your github link doesn't work.

Computed properties cannot be @State variables, so there's that. And if the property is computed from the values of existing @State properties or properties of an @ObservedObject, it doesn't need to be anyway.

But here's a simple example:

struct ContentView: View {
    @StateObject var expenses = Expenses()

    private var totalExpenses: Double {
        //just total up all the expense amounts from expenses
        expenses.items.reduce(0) { accumulatedAmount, currentItem in
            return accumulatedAmount + currentItem.amount
        }
    }

    var body: some View {
        VStack(spacing: 40) {
            Text("\(totalExpenses)")
            Button("Add Item") {
                expenses.items.append(ExpenseItem(name: "Something \(Int.random(in: 0...10_000))",
                                                      type: Int.random(in: 0...10).isMultiple(of: 2) ? "Personal" : "Business",
                                                      amount: Double.random(in: 1.0 ... 15.0)))
            }
        }
    }
}

2      

The way I did it was to use a function

func totalAmount(for expenseItem: [ExpenseItem]) -> Double {
    expenseItem.map { $0.amount }.reduce(0, +)
}

GitHub/iExpense

Or could try

var totalExpenses: Double {
  items.map { $0.amount }.reduce(0, +)
}

2      

Thank you both for the solutions!!

I got them both to work, and it was a good way to learn more about higher-order functions :D

2      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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.