TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SOLVED: iExpense Challenge onDelete

Forums > 100 Days of SwiftUI

I'm stuck on how to delete when there are sections present in the list of expenses.

First I created the two sections using .filter to filter based on Personal vs Business.

            Section {
                ForEach(expenses.items.filter( { $0.type == "Personal" } )) { item in
                    HStack {
                        VStack(alignment: .leading) {
                            Text(item.name)
                                .font(.headline)
                            Text(item.type)
                        }

                        Spacer()
                        amountView(amount: item.amount)
                    }
                }
                .onDelete(perform: removeItems)
            }

            Section {
                ForEach(expenses.items.filter( { $0.type == "Business" } )) { item in
                    HStack {
                        VStack(alignment: .leading) {
                            Text(item.name)
                                .font(.headline)
                            Text(item.type)
                        }

                        Spacer()
                        amountView(amount: item.amount)
                    }
                }
                .onDelete(perform: removeItems)
            }

This doesn't work. It deletes the wrong row. Then I thought I could create two removeItems functions, one called removePersonalItems and one called removeBusinessItems.

I then modified the functions as follows:

func removePersonalItems(at offsets: IndexSet) {
    expenses.items.filter( { $0.type == "Personal" } ).remove(atOffsets: offsets)
}

But this fails as .filter returns an immutable array.

Then I thought maybe I could delete by ID, since ExpenseItem conforms to Identifiable but I can find no way to do so. onDelete doesn't seem to capture the id of the item.

Then I thought maybe there's something I can do with an IndexSet, some method or property that would be of use. But without being able to see what is being sent to removeItems, it's difficult to figure out.

So I figured I'd print the offsets parameter to the console, but using print(offsets) in removeItems does nothing. Nothing is displayed on the console at all.

So what's the solution?

2      

The only thing I can think of that would work, which I'll do if there's no solution forthcoming here, would be to have two arrays, one for personal and one for business. The type property would be removed and would instead dictate which array gets the new expense item.

2      

I didn't use Array.filter I just used if to create my separate sections.

It seems to delete the correct items every time this way. But I remember thinking that it was strange that I didn't have to do anything special to make sure that the proper items were deleted, since Paul specifically mentions that we have to be careful about how we delete the items.

List {
    Section {
        ForEach(expenses.items) { item in
            if item.type == "business" {
                HStack {
                    Text(item.name)
                        .font(.headline)

                    Spacer()

                    Text(item.amount, format: .currency(code: Locale.current.currencyCode ?? "USD"))
                        .foregroundColor(itemColor(itemAmount: item.amount))
                }
            }
        }
        .onDelete(perform: removeItems)
    } header: {
        Text("Business Expenses")
    }

    Section {
        ForEach(expenses.items) { item in
            if item.type == "personal" {
                HStack {
                    Text(item.name)
                        .font(.headline)

                    Spacer()

                    Text(item.amount, format: .currency(code: Locale.current.currencyCode ?? "USD"))
                        .foregroundColor(itemColor(itemAmount: item.amount))
                }
            }
        }
        .onDelete(perform: removeItems)
    } header: {
        Text("Personal Expenses")
    }
}

It's still just using

func removeItems(at offsets: IndexSet) {
    expenses.items.remove(atOffsets: offsets)
}

2      

@Bnerd  

When you use .filter it returns a NEW array, thus the onDelete using the below

func removeItems(at offsets: IndexSet) {
    expenses.items.remove(atOffsets: offsets)
}

will not work. Making separate arrays will work, but is it worth it? Unless there is a way to modify the removeItems method..tried a bit with no much success

2      

Hacking with Swift is sponsored by String Catalog.

SPONSORED Get accurate app localizations in minutes using AI. Choose your languages & receive translations for 40+ markets!

Localize My App

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.