Changing the SwiftData object by copy in func

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

There is the following code:

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"
    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
                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()

What I tried:

  • 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

What I expect:

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


  • 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