Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI - Indexset to index in array

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.

like image 963
E.pojken Avatar asked Jan 22 '20 21:01

E.pojken


People also ask

How to get the index of an item in an array swiftui?

To get the first index of an item in an array in Swift, use the array. firstIndex(where:) method. print(i1!)

How to get index of string in array Swift?

To find the index of a specific element in an Array in Swift, call firstIndex() method and pass the specific element for of parameter. Array. firstIndex(of: Element) returns the index of the first match of specified element in the array. If specified element is not present in the array, then this method returns nil .

What is an Indexset in Swift?

A collection of unique integer values that represent the indexes of elements in another collection.


2 Answers

.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])
}
like image 147
user3441734 Avatar answered Sep 20 '22 08:09

user3441734


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 }
}
like image 43
Asperi Avatar answered Sep 20 '22 08:09

Asperi