Home > database >  SwiftUI remove data into a structured array via a button in a ForEach
SwiftUI remove data into a structured array via a button in a ForEach

Time:12-06

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.

  • Related