如何从 SwiftData 查询将数据传递到子视图

问题描述 投票:0回答:1

我正在通过一个项目学习 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)
        }
    }
}
swiftui swift-data swiftui-navigationstack
1个回答
0
投票

我建议您阅读更多有关如何使用

@Bindable
的教程,以便您正确理解这一点。

您应该使用 Bindable 而不是 Binding 在视图中声明属性,所以应该如此

@Bindable var account: Account

当调用具有此类属性的视图时,您不需要需要对传递的值执行任何特殊操作

NavigationLink(destination: TransactionsView(account: account))

至于您的实际代码,在向帐户添加交易时根本不需要使用

@Bindable
,因为
Account
对象并未真正更新。这可能有点令人困惑,但是当向帐户对象添加交易时,您正在更新它们之间的关系,而不是帐户对象本身。

因此,我们可以在两个视图中删除

@Bindable
属性的
Account
并将声明更改为

let account: Account
© www.soinside.com 2019 - 2024. All rights reserved.