I'm trying to remove a line in my structured array when user click on the delete button. But as I use a foreach to load all my array lines into a specific subview I don't know how to pass the index of the ForEach into my subview to delete my line...
My code is like this,
ScrollView{
VStack {
ForEach(planeLibrary.testPlane){plane in
ZStack {
RoundedRectangle(cornerRadius: 16, style: .continuous)
.fill(Color.white)
.shadow(color: Color(Color.RGBColorSpace.sRGB, white: 0, opacity: 0.2), radius: 4)
PlaneCellView(plane: plane, planeLibrary: planeLibrary, line: ???)
}
}
}.padding(.horizontal, 16)
}
And my PlaneCellView :
@State var plane: Plane
@ObservedObject var planeLibrary: PlaneLibrary
var line: Int
var body: some View {
//...
VStack(alignment: .leading) {
Text(plane.planeImat)
.font(.title)
.fontWeight(.bold)
Text(plane.planeType)
HStack{
Text(plane.isSe ? "SE" : "ME")
Text(plane.isNight ? "- Night" : "")
Text(plane.isIfr ? "- IFR" : "")
}
}
Spacer()
Button {
// HERE I don't know how to delete my array line ...
planeLibrary.testPlane.remove(at: line)
} label: {
Image(systemName: "trash.circle")
.foregroundColor(.red)
.font(.system(size: 30))
}
//...
}
My Plane library :
struct Plane: Identifiable{
let id = UUID().uuidString
let planeImat: String
let planeType: String
let isSe: Bool
let isIfr: Bool
let isNight: Bool
let autoID: String
init (planeImat: String, planeType: String, isSe: Bool, isIfr: Bool, isNight: Bool, autoID: String){
self.planeType = planeType
self.planeImat = planeImat
self.isSe = isSe
self.isIfr = isIfr
self.isNight = isNight
self.autoID = autoID
}
init(config: NewPlaneConfig){
self.planeImat = config.imat
self.planeType = config.type
self.isSe = config.isSe
self.isIfr = config.isIfr
self.isNight = config.isNight
self.autoID = config.autoID
}
}
I've already try to add id: \.self
as I was able to find on this forum but without any success.
CodePudding user response:
You haven't actually included PlaneLibrary, so I will assume that planeLibrary.testPlane is an array of Plane structs.
There are many ways of solving this, including changing testPlane to be a Dictionary of Plane structs (indexed by id), or if order is important, in an OrderedDictionary (add the swift-collections
package to your project and import OrderedCollections
in the file where it is used). You could use testPlane.removeValue(at: id)
to remove the plane from either type of dictionary.
If you keep it as an array, but your array might be large and you're worried about run-time efficiency, the best thing to do is to change your ForEach to include the index of the planes in the loop.
It would look something like this:
ForEach(Array(planeLibrary.testPlane.enumerated()), id: \.element.id) { index, plane in
// In this code you can use either plane, or index.
...
// UI code
Text(plane.autoID)
...
{ // remove closure
planeLibrary.testPlane.remove(at: index)
}
}
But if the array is of reasonable size, you could keep it as it is now and use testPlane.remove(where:)
to find it by id
at the time of deletion. The code for this is much simpler and easier to read and understand, so it should probably be your first choice. Optimise for large lists later, if you need.