问题
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.
回答1:
.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])
}
回答2:
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 }
}
来源:https://stackoverflow.com/questions/59868180/swiftui-indexset-to-index-in-array