我正在通过一个项目学习 Swift。我正在创建一个应用程序,用户可以在其中创建多个
accounts
并在每个帐户中注册 transactions
。与我的问题相关的模型和视图如下所示。
当用户点击某个帐户时,他们将进入交易视图,其中显示该所选帐户的所有交易。然后,用户可以向帐户添加新交易。
我不清楚的是如何在使用
TransactionView
时将所选帐户传递给AddTransactionView
和NavigationStack
。我当前的代码抛出错误:Cannot convert value of type 'Bindable<Account>' to expected argument type 'Binding<Account>'
如果我将
Bindable
更改为 .constant
似乎可行,但我不确定这是否正确。
希望能解释一下为什么我所拥有的功能不起作用。
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
}
}
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)
}
}
}
我建议您阅读更多有关如何使用
@Bindable
的教程,以便您正确理解这一点。
您应该使用 Bindable 而不是 Binding 在视图中声明属性,所以应该如此
@Bindable var account: Account
当调用具有此类属性的视图时,您不需要需要对传递的值执行任何特殊操作
NavigationLink(destination: TransactionsView(account: account))
至于您的实际代码,在向帐户添加交易时根本不需要使用
@Bindable
,因为 Account
对象并未真正更新。这可能有点令人困惑,但是当向帐户对象添加交易时,您正在更新它们之间的关系,而不是帐户对象本身。
因此,我们可以在两个视图中删除
@Bindable
属性的 Account
并将声明更改为
let account: Account