Welcome to this video demo on adding a totals section to the list view in the budget-tracking app. By the end of this demo, you’ll understand how to display the total expenses and income in a way that makes the totaling logic testable outside of SwiftUI. Let’s get started!
Open the starter Xcode project located at 03-leveraging-observation-for-shared-state-management/03-demo/Starter/MyBudget.xcodeproj.
Step 1: Implementing an Observable FinancialData Class
First, you’ll create a FinancialData class to encapsulate the list of financial entries and the logic to compute total expenses and income. This approach keeps the model layer clean and separates the business logic from the UI layer.
Open FinancialEntryModel.swift, and add the new class above the FinancialEntry class:
@Observable
final class FinancialData {
var entries: [FinancialEntry] = []
var totalExpenses: Double {
entries.filter { $0.isExpense }.reduce(0) { $0 + $1.amount }
}
var totalIncome: Double {
entries.filter { !$0.isExpense }.reduce(0) { $0 + $1.amount }
}
}
Here, you’ve defined the FinancialData class with an entries array to store FinancialEntry objects. You also added computed properties totalExpenses and totalIncome that calculate the sums dynamically. This design makes it easy to test these computations independently from the SwiftUI views.
Step 2: Integrating FinancialData Into BudgetTrackerApp
Next, you’ll integrate the FinancialData class into the app by adding it as a state property in the BudgetTrackerApp struct. This ensures that the financial data is available to be passed throughout the app.
Switch to BudgetTrackerApp.swift, and add the following state property to BudgetTrackerApp:
@State private var financialData = FinancialData()
Adding financialData as a state property in the app’s main App struct allows you to pass this data to all views, keeping the UI in sync with any changes to the source of truth for financial data.
Step 3: Updating ContentView to Use FinancialData
Now, you’ll update ContentView to use the FinancialData object instead of managing its own list of entries. This centralizes data management and prepares you to display the totals.
In ContentView, start modifying the properties and update the SwiftUI preview.
First, replace the entries state property with @Bindable var financialData: FinancialData:
@Bindable var financialData: FinancialData
financialData needs to be bindable because AddFinancialEntryView needs a binding to financialData’s array of entries. AddFinancialEntryView uses the binding to insert new entries into the array.
Pass the app’s financial data into the ContentView inside BudgetTrackerApp’s WindowGroup:
ContentView(financialData: financialData)
At the bottom of the file, update the preview to pass a financial data object into ContentView:
#Preview {
ContentView(financialData: FinancialData())
}
Back in ContentView, in the ForEach inside the “Entries” Section, update the reference to entries to financialData.entries:
ForEach(financialData.entries) { entry in
Inside the sheet view modifier, update AddFinancialEntryView’s financial entries parameter from $entries to $financialData.entries:
financialEntries: $financialData.entries)
This change ensures that ContentView operates on the same set of financial data as the rest of the app, maintaining consistency and enabling dynamic updates to the UI as data changes.
Step 4: Adding a Totals Section to the List View
Finally, add a new section to the list view that displays the computed total expenses and income. This gives users a quick overview of their financial status.
Add a new totals section inside the List in ContentView.swift, before the “Entries” section:
Section(header: Text("Totals")) {
HStack {
Text("Total Expenses")
Spacer()
Text("$\(financialData.totalExpenses, specifier: "%.2f")")
.foregroundColor(.red)
}
HStack {
Text("Total Income")
Spacer()
Text("$\(financialData.totalIncome, specifier: "%.2f")")
.foregroundColor(.green)
}
}
By adding this section, you provide a clear, real-time view of the total expenses and income.
Build and run the app to see your changes in action. Add and edit entries, and watch as the totals update instantly.
Wrap-Up
And that’s it! You’ve now added a totals section to the budget-tracking app, improving its functionality and testability. Great job on finishing the demo!