18

I am using ForEach within a NavigationView and list combined with a function called when the user deletes a row using .onDelete() as per below.

struct PeriodListView: View {
@ObservedObject var theperiodlist = ThePeriodList()
@EnvironmentObject var theprofile: TheProfile

@State private var showingAddPeriod = false

var dateFormatter: DateFormatter {
    let formatter = DateFormatter()
    formatter.dateStyle = .long
    return formatter
}

var body: some View {
    NavigationView {
        List {
            ForEach(theperiodlist.periods) {period in
                PeriodRow(period: period)
            }
            .onDelete(perform: removePeriods)
        }
        .navigationBarTitle("Periods")
            .navigationBarItems(trailing:
                Button(action: {self.showingAddPeriod = true}) {
                    Image(systemName: "plus")
                }
            )
        .sheet(isPresented: $showingAddPeriod) {
            AddPeriod(theperiodlist: self.theperiodlist).environmentObject(self.theprofile)
        }
    }
}
func removePeriods(at offsets: IndexSet) {
    AdjustProfileRemove(period: theperiodlist.periods[XXX])
    theperiodlist.periods.remove(atOffsets: offsets)
}

I have a separate function (AdjustProfileRemove(period)) which I want to call with the removed period as the variable - e.g. I want to find XXX in AdjustProfileRemove(period: theperiodlist.periods[XXX]). Is there a simple way to do this (I am guessing from IndexSet) or am I missing something fundamental?

Thanks.

2
  • It is a little unclear to me what your'e asking. Could you maybe outline the AdjustProfileRemove(_ : Period) function? Commented Jan 22, 2020 at 21:07
  • I just started out with SwiftUI and trying to build my first project. The AdjustProfileRemove(_ : Period) function takes a Period() as input (which are the elements in the theperiodlist.periods-list) and returns a set of integers which I want to use. So I am looking for the index of the theperiodlist.periods-list obtained when the user deletes that particular Period() from the NavigationView. I hope this clarifies? Commented Jan 22, 2020 at 21:17

2 Answers 2

25

.onDelete is declared as

@inlinable public func onDelete(perform action: ((IndexSet) -> Void)?) -> some DynamicViewContent

IndexSet is simply Set of all indexes of the elements in the array to remove. Let try this example

var arr = ["A", "B", "C", "D", "E"]
let idxs = IndexSet([1, 3])

idxs.forEach { (i) in
    arr.remove(at: i)
}
print(arr)

so the resulting arr is now

["A", "C", "D"]

The reason, why .onDelete use IndexSet is that more than one row in List could be selected for delete operation.

BE CAREFULL! see the resulting array! Actually removing elements one by one needs some logic ...

Let's try

var arr = ["A", "B", "C", "D", "E"]
let idxs = IndexSet([1, 3])

idxs.sorted(by: > ).forEach { (i) in
    arr.remove(at: i)
}
print(arr)

it works now as you expected, is it? the result now is

["A", "C", "E"]

Based on

theperiodlist.periods.remove(atOffsets: offsets)

it seems, that the ThePeriodList already has build-in function with required functionality.

in your case just replace

AdjustProfileRemove(period: theperiodlist.periods[XXX])

with

offsets.sorted(by: > ).forEach { (i) in
    AdjustProfileRemove(period: theperiodlist.periods[i])
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your good input. Did not realise that IndexSet could contain several indices. I used the solution proposed by Asperi above.
@user3612450 is up to you. i see Asperi's solution overcomplicated, it could be done with two lines of code in your code base :-). Important is, that you've got the point.
@user3612450 i updated my answer how to use it in your code
3

Here is possible approach (taking into account that in general offsets can contain many indexes)

func removePeriods(at offsets: IndexSet) {
    theperiodlist.periods = 
        theperiodlist.periods.enumerated().filter { (i, item) -> Bool in
            let removed = offsets.contains(i)
            if removed {
                AdjustProfileRemove(period: item)
            }
            return !removed
        }.map { $0.1 }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.