Reputation: 25
As far as I know, any object is passed to a function by copying unless inout is specified
This is how it always worked until I started integrating SwiftData into my app
import SwiftUI
import SwiftData
struct AccountCircleList: View {
@Query var accounts: [Account]
@Query var currencies: [Currency]
var groupedAccounts: [Account] {
return groupAccounts(accounts: tmp, currencies: currencies)
}
...
}
// addictional Q: Maybe there is a way not to transmit exchange currencies directly?
func groupAccounts(accounts: [Account], currencies: [Currency]) -> [Account] {
/////// this is just illustrative example
// Before it was "Cash"
print(accounts[0].name)
accounts[0].name += "Some" // After this I see "CashSomeSomeSomeSome..." in console
///////
var ratesMap: [String: Decimal] {
Dictionary(uniqueKeysWithValues: currencies.map { ($0.isoCode, $0.rate ) })
}
for (i, account) in accounts.enumerated() {
if let parentAccountID = account.parentAccountID {
let parentAccountIndex = accounts.firstIndex { $0.id == parentAccountID }
let parentAccount = accounts[parentAccountIndex!]
if account.visible {
// Here we change the value of the array in usual case
accounts[parentAccountIndex!].childrenAccounts.append(account)
if account.accounting {
let relation = (ratesMap[parentAccount.currency] ?? 1) / (ratesMap[account.currency] ?? 1)
accounts[parentAccountIndex!].budget += account.budget * relation
accounts[parentAccountIndex!].remainder += account.remainder * relation
}
}
accounts[i].isChild = true // And here
}
}
return accounts
}
This function groups child accounts into parent accounts and calculates the overall statistics
But it turns out that it changes the overall accounts array, which triggers the grouping function again and again, infinitely, until the memory runs out
Would there be any possibility to do var accountsCopy = accounts.copy()
I tried making a subView and calling the groupAccounts()
function from it, but it resulted in the same result
Assign another variable to accounts in a function and change it: var tmp = accounts
Also I make another class Account2
with same fields and convert accounts
to accounts2
in func, it helped but it looks ugly
Behavior in which the function will not change the original array and the function will be called only once when opening the screen or changing data in the database
Upvotes: 0
Views: 526
Reputation: 25
The solution of my problem was the @transient
attribute, which says to SwiftData to ignore this field, thereby making the childrenAccounts
field with this at attribute and adding two new aggregatedBudget
and aggregatedRemainder
, I can’t change the “sensitive” data that SwiftData reacts
@Transient var childrenAccounts: [Account] = []
@Transient var aggregatedBudget: Decimal = 0
@Transient var aggregatedRemainder: Decimal = 0
Upvotes: 0