Я изучаю 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)
}
}
}
вам нужен еще один @Query для транзакций
отвечает ли этот ТАК-пост на ваш вопрос: stackoverflow.com/questions/76464884/…
@JoakimDanielson Я изменяю свойство транзакций объекта Account в представлении внука, т. е. AddTransactionView.
@workingdogsupportUkraine нет, потому что я использую Bindable, как следует из ответа, и он не работает.
@malhal ах, так что передай учетную запись и запроси учетную запись еще раз. Мне это кажется немного неэффективным — когда я уже знаю, какую учетную запись изменить, не запрашивая данные во второй раз.
Нет, запрос транзакций с использованием предиката account =
Тогда попробуйте Bindable
Ваш код показывает, что вы не используете Bindable, как рекомендовано. Вы используете @Binding var account: Account в TransactionsView и AddTransactionView. Используйте @Bindable var account: Account





Я бы посоветовал вам прочитать больше и посмотреть некоторые руководства по использованию @Bindable, чтобы вы правильно это поняли.
Вы должны объявлять свойства в своем представлении, используя Bindable, а не Binding, поэтому это должно быть
@Bindable var account: Account
и при вызове представления с таким свойством не нужно ничего особенного делать с переданным значением
NavigationLink(destination: TransactionsView(account: account))
Что касается вашего фактического кода, вам вообще не нужно использовать @Bindable при добавлении транзакций в учетную запись, поскольку объект Account на самом деле не обновляется. Это может немного сбивать с толку, но при добавлении транзакции к объекту учетной записи вы обновляете отношения между ними, а не сам объект учетной записи.
Итак, с учетом сказанного, мы можем удалить @Bindable для свойства Account в обоих дочерних представлениях и изменить объявление на
let account: Account
Для типов моделей вам следует использовать Bindable, а не Binding. Но в этом случае похоже, что вам вообще не нужен Bindable, поскольку вы не изменяете объект Account в дочернем представлении.