5

Overview

im doing a simple app with core data I have two entity users and territory the app shows a list of the users in sections by territory the problem is In the delete action the list delete the user from the first section if I try to delete the second user from the second section it delete the second user from the first section.

I think index set is getting wrong sending the index of the section but when I try to change the onDelete to my nested forEach don't work

Here is the code

import SwiftUI

struct ContentView: View {
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: User.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \User.name, ascending: true)]) var users: FetchedResults<User>
    @FetchRequest(entity: Territory.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Territory.name, ascending: true)]) var territories: FetchedResults<Territory>
    @State private var showAddUser = false


       var body: some View {
           GeometryReader{ geometry in
               NavigationView {
                   ZStack {

                       List {
                           ForEach(self.territories, id: \.self) { territorie in
                            Section(header: Text(territorie.wrappedName)) {
                                ForEach(territorie.usersArray, id: \.self) { user in
                                    NavigationLink(destination: UserView(user: user)) {
                                        VStack{
                                            HStack{
                                               Text("user")
                                                Spacer()
                                                Text(user.dayLastVisit)
                                                    .padding(.horizontal)
                                            }
                                            HStack {
                                                Text(user.wrappedEmoji)
                                                    .font(.largeTitle)
                                                VStack(alignment: .leading) {
                                                    Text("\(user.wrappedName + " " + user.wrappedLastName)")
                                                        .font(.headline)
                                                    Text(user.wrappedType)

                                                }
                                                Spacer()
                                            }
                                        }

                                    }
                                }.onDelete(perform: self.deleteItem)
                            }
                           }



                       }
                       .listStyle(GroupedListStyle())
                       .environment(\.horizontalSizeClass, .regular)

                       VStack {
                           Button(action:{ self.showAddRUser.toggle()}){
                               ButtonPlus(icon:"plus")}
                           .offset(x: (geometry.size.width * 0.40), y: (geometry.size.height  * 0.38))
                           .sheet(isPresented: self.$showAddUser){
                               NewUserView().environment(\.managedObjectContext, self.moc)
                                  }
                       }
                   }
               .navigationBarTitle("Users")
                   .navigationBarItems( trailing: HStack {
                    EditButton()
                    Button(action:{self.showAddUser.toggle()}){
                    ButtonNew(text:"Nueva")}
                    }

                    .sheet(isPresented: self.$showAddUser){
                        NewUserView().environment(\.managedObjectContext, self.moc)
                   }
                   )

               }
           }
       }
    func deleteItem(at offsets: IndexSet) {
        for offset in offsets { 
            let user = users[offset]

            //borarlo del context
            moc.delete(user)

        }
        try? moc.save()
    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

im learning swift and swiftui so im would appreciate any help

3 Answers 3

6

You’ll need to pass in a section index as well as the row index, so that you know which nested item to delete. Something like this.

.onDelete { self.deleteItem(at: $0, in: sectionIndex) }

And change your function to accept that section index:

func deleteItem(at offsets: IndexSet, in: Int)

In your case you can probably pass in something like territorie.id as the section index, and use that to delete the correct item. Or pass in the territorie object - whatever you need to get to the correct user. Only the index won’t get you there. Hope it all makes sense!

Sign up to request clarification or add additional context in comments.

2 Comments

hi thanks! I have User.id and and Territory.id both UUID and territory have a relationship one to many with User, to pass the territorie.id as the section index I just have to change the .self for the .id?
it worked! I just passed the territorie object then instead of the users[offset] I use the territorie.usersArray of the object to delete the correct user
2

For me, the solution was the following:

ForEach(self.territories, id: \.self) { territorie in

    Section(header: Text(territorie.wrappedName)) {

        ForEach(territorie.usersArray, id: \.self) { user in
            // your code here
        }
        .onDelete { indexSet in
            for index in indexSet {
                moc.delete(territorie[user])
            }
                
            // update the view context
            moc.save()
        }
    }
}

The index in indexSet returns the item that should be deleted in that specific section. So if I delete the first item of a section, it returns 0.

The territorie returns a list of all the items that are contained in that section. So using territorie[index] will return the specific user object you want to delete.

Now that we have the object we want to delete, we can pass it to moc.delete(territorie[index]). Finally, we save it with moc.save().

Sidenote: although Misael used the variable 'territorie', I prefer to use the variable name section.

Comments

2

So thanks to the help of Kevin Renskers who found a solution. I just add a .onDelete { self.deleteItem(at: $0, in: territorie)} to my function then I use the same arrayUsers from the territory.

 func deleteItem(at offsets: IndexSet, in ter: Territory) {
        
        for offset in offsets {
             let user =  ter.usersArray[offset] 
            moc.delete(user)
            
        }
        try? moc.save()
    }

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.