I'm learning Swift through a project. I'm creating an app where the user can create multiple accounts
and register transactions
within each account. The models and views that are relevant to my question are shown below.
When the user taps on an account, they are taken to the transactions view which shows all the transactions for that selected account. The user can then add a new transaction to the account.
What's not clear to me is how to pass the selected account to the TransactionView
and the AddTransactionView
when using a NavigationStack
. The code I currently have throws the error: Cannot convert value of type 'Bindable<Account>' to expected argument type 'Binding<Account>'
If I change Bindable
to .constant
that seems to work, but I'm not sure if that's correct.
Would appreciate an explanation of why what I have doesn't work as well.
Models
import Foundation
import SwiftData
@Model
final class Account {
var created: Date
var name: String
var transactions: [Transaction]
init(created: Date, name: String, transactions: [Transaction] = []) {
self.created = created
self.name = name
self.transactions = transactions
}
}
import Foundation
import SwiftData
@Model
final class Transaction {
var date: Date
var value: Decimal?
init(date: Date, value: Decimal? = nil) {
self.date = date
self.value = value
}
}
Views
import SwiftData
import SwiftUI
struct AccountsView: View {
@Query private var accounts: [Account]
@State private var isAddingAccount = false
var body: some View {
NavigationStack {
List {
ForEach(accounts) { account in
NavigationLink(destination: TransactionsView(account: Bindable(account))) {
Text(account.name)
}
}
}
.navigationTitle("Accounts")
.toolbar {
ToolbarItem {
Button {
isAddingAccount = true
} label: {
Label("Add Account", systemImage: "plus")
}
}
}
}
.fullScreenCover(isPresented: $isAddingAccount) {
AddAccountView(isPresented: $isAddingAccount)
}
}
}
import SwiftUI
struct TransactionsView: View {
@Binding var account: Account
var transactions: [Transaction] { account.transactions }
@State private var isAddingTransaction = false
var body: some View {
NavigationStack {
List {
ForEach(transactions) { transaction in
NavigationLink(destination: Text(transaction.date.description)) {
Text(transaction.value!.formatted())
}
}
}
.toolbar {
ToolbarItem {
Button {
isAddingTransaction = true
} label: {
Label("Add transaction", systemImage: "plus")
}
}
}
}
.fullScreenCover(isPresented: $isAddingTransaction) {
AddTransactionView(isPresented: $isAddingTransaction, account: $account)
}
}
}
import SwiftUI
struct AddTransactionView: View {
@Binding var isPresented: Bool
@Binding var account: Account
@State private var newTransaction = Transaction(date: Date())
var body: some View {
NavigationView {
VStack {
Form {
DatePicker(selection: $newTransaction.date, displayedComponents: .date) { Text("Date") }
.datePickerStyle(.compact)
TextField(value: $newTransaction.value, format: .number) {
Text("Value")
}
}
Button("Add") {
addTransaction(transaction: newTransaction)
isPresented = false
}
}
.navigationTitle("Add transaction")
.navigationBarItems(trailing: Button("Cancel") {
isPresented = false
})
}
}
private func addTransaction(transaction: Transaction) {
withAnimation {
account.transactions.append(transaction)
}
}
}
@Query
for transactions