bonavii
bonavii

Reputation: 25

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

What I tried:

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

Upvotes: 0

Views: 526

Answers (1)

bonavii
bonavii

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

Related Questions