微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法在部分列表视图中编辑/删除正确的项目

如何解决无法在部分列表视图中编辑/删除正确的项目

我有下面的视图,其中包含包含已完成/未完成部分的任务列表,但在尝试编辑列表中的一项时,始终选择该部分的最后一项,甚至不允许删除。它看起来在测试部分内的所有记录都是一条记录时,因此删除幻灯片不起作用,并且在编辑时获取最后一条记录。在完整代码下方,您可以尝试帮助我确定问题所在。

import SwiftUI
import CoreData
import UserNotifications

struct ListView: View {
    
    @Environment(\.presentationMode) var presentationMode
    @Environment(\.managedobjectContext) var viewContext
    
    @FetchRequest(fetchRequest: Task.taskList(),animation: .default) private var items: FetchedResults<Task>
    
    @State var isAddFormPresented: Bool = false
    
    @State var taskToEdit: Task?
    
    init(predicate: nspredicate?,sortDescriptor: NSSortDescriptor) {
        let fetchRequest = NSFetchRequest<Task>(entityName: Task.entity().name ?? "Task")
        fetchRequest.sortDescriptors = [sortDescriptor]
        
        if let predicate = predicate {
            fetchRequest.predicate = predicate
        }
        _items = FetchRequest(fetchRequest: fetchRequest)
        
        UITableViewCell.appearance().backgroundColor = .white
        UITableView.appearance().backgroundColor = .white
        
    }
    
    var body: some View {
        
        let data = groupedEntries(self.items)
        
        vstack(alignment: .center) {
            
            if data.isEmpty {
                
                Spacer()
                
                Image("empty")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: 250,height: 250)
                    .clipShape(Circle())
                    .overlay(Circle().stroke(Color.pink,linewidth: 2))
                
                Spacer()
                
            } else {
                
                List {
                    
                    ForEach(data,id: \.self) { (section: [Task]) in
                        
                        Section(header: Text(section[0].isComplete == false ? "Incomplete" : "Completed")
                                    .font(.body)
                                    .foregroundColor(section[0].isComplete == false ? Color.pink : Color.green)
                        ){
                            
                            self.completedView(section: section)
                            
                        }
                        .sheet(item: $taskToEdit,ondismiss: {
                            self.taskToEdit = nil
                        }) { task in
                            TaskFormView(
                                taskToEdit: task,name: task.name!,taskDetails: task.taskDetails ?? "",important: TaskType2(rawValue: task.important ?? "") ?? .none,urgent: TaskType(rawValue: task.urgent ?? "") ?? .none,secondaryCategory: Category(rawValue: task.secondaryCategory ?? "") ?? .other,isComplete: task.isComplete,dateAdded: task.dateAdded ?? Date()
                            )
                        }
                    }
                }
                .listStyle(SidebarListStyle())
                
                HStack {
                    
                    Spacer()
                    
                    Button(action: addTapped) {
                        Image(systemName: "plus.circle.fill")
                            .resizable()
                            .frame(width: 30,height: 30)
                            .shadow(radius: 20)
                    }
                    .padding(.trailing,40)
                    .padding(.bottom,24)
                    .accentColor(Color(UIColor.systemRed))
                }
            }
        }
        .frame(maxWidth: .infinity,maxHeight: .infinity)
        .background(Color(UIColor.systemYellow).opacity(0.5))
        .edgesIgnoringSafeArea(.all)
        .sheet(isPresented: $isAddFormPresented) {
            
            TaskFormView()
                .environment(\.managedobjectContext,PersistenceController.shared.container.viewContext)
        }
    }
    
    func groupedEntries(_ result : FetchedResults<Task>) -> [[Task]] {
        
        return Dictionary(grouping: result) { (element : Task) in
            
            element.isComplete
        }
        .values.sorted() { $0[0].dateAdded! < $1[0].dateAdded! }
    }
    
    func completedView(section: [Task]) -> some View {
        
        ForEach(section,id: \.id) { task in
            
            Button(action: {
                
                taskToEdit = task
                
            }) {
                HStack {
                    
                    CategoryRowView(category: Category(rawValue: task.secondaryCategory!)!,dateAdded: task.dateAdded!)
                    
                    vstack(alignment: .leading) {
                        
                        HStack {
                            
                            if task.isComplete != false {
                                Image(systemName: "checkmark.circle.fill")
                                    .foregroundColor(.pink)
                                    .padding(.top,10)
                                    .padding(.leading,5)
                            }
                            Text(task.name!)
                                .font(.system(size: 20,weight: .regular,design: .default))
                                .foregroundColor(.primary)
                                .padding(.top,10)
                                .padding(.leading,5)
                        }
                        Spacer()
                        
                        HStack {
                            
                            Image(systemName: "tag.fill")
                                .foregroundColor(.secondary)
                            Text(task.important == "none" ? "Not Important" : "Important")
                                .font(.system(size: 12,design: .default))
                                .foregroundColor(.secondary)
                                .padding(.vertical)
                            Text(task.urgent == "none" ? "Not Urgent" : "Urgent")
                                .font(.system(size: 12,design: .default))
                                .foregroundColor(.secondary)
                                .padding(.vertical)
                        }
                        .padding(.leading,5)
                    }
                    .padding(.trailing,2)
                    Spacer()
                }
                .frame(height: 140)
                .background(Color(.systemBackground))
                .cornerRadius(10)
                .shadow(color: .black,radius: 4,x: 0,y: 0)
                .padding(.vertical,5)
            }
        }
        .onDelete { row in
            deleteEntry(row: row,in: section)
        }
    }
    
    func addTapped() {
        
        isAddFormPresented.toggle()
    }
    
    private func onReturnTapped() {
        
        self.presentationMode.wrappedValue.dismiss()
    }
    
    func deleteEntry(row: IndexSet,in section: [Task]) {
        
        let task = section[row.first!]
        
        UNUserNotificationCenter.current().removeAllDeliverednotifications()
        
        UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [task.id!.uuidString])
        
        viewContext.delete(task)
        
        do {
            
            try viewContext.save()
            
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError),\(nsError.userInfo)")
        }
    }
}

private let itemFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "dd MMM"
    
    return formatter
}()

print screen of the list view

解决方法

这是您的 View 的简化版本,因此您可以了解 NSFetchedResultsController 如何完成这项工作。您需要一个 List 才能滑动要删除的行。

import SwiftUI
import CoreData
class TaskListViewModel: ObservableObject {
    let persistenceController = PersistenceController.previewAware()
    @Published var fetchedResultsController: NSFetchedResultsController<Task>?
    
    init() {
        setupController()
    }
    func setupController() {
        do{
            fetchedResultsController = try retrieveFetchedController(sortDescriptors: nil,predicate: nil,sectionNameKeyPath: #keyPath(Task.isComplete))
        }catch{
            print(error)
        }
    }
    func deleteObject(object: Task) {
        persistenceController.container.viewContext.delete(object)
        save()
    }
    func save() {
        do {
            if persistenceController.container.viewContext.hasChanges{
                try persistenceController.container.viewContext.save()
                objectWillChange.send()
            }else{
            }
        } catch {
            print(error)
        }
    }
}
//MARK: FetchedResultsController setup
extension TaskListViewModel{
    func retrieveFetchedController(sortDescriptors: [NSSortDescriptor]?,predicate: NSPredicate?,sectionNameKeyPath: String) throws -> NSFetchedResultsController<Task> {
        
        return try initFetchedResultsController(sortDescriptors: sortDescriptors,predicate: predicate,sectionNameKeyPath: sectionNameKeyPath)
    }
    private func initFetchedResultsController(sortDescriptors: [NSSortDescriptor]?,sectionNameKeyPath: String) throws -> NSFetchedResultsController<Task> {
        fetchedResultsController = getFetchedResultsController(sortDescriptors: sortDescriptors,sectionNameKeyPath: sectionNameKeyPath)
        do {
            try fetchedResultsController!.performFetch()
            return fetchedResultsController!
            
        } catch {
            print( error)
            throw error
        }
    }
    func getFetchedResultsController(sortDescriptors: [NSSortDescriptor]?,sectionNameKeyPath: String) -> NSFetchedResultsController<Task> {
        
        return NSFetchedResultsController(fetchRequest: getEntityFetchRequest(sortDescriptors: sortDescriptors,predicate: predicate),managedObjectContext: persistenceController.container.viewContext,sectionNameKeyPath: sectionNameKeyPath,cacheName: nil)
    }
    private func getEntityFetchRequest(sortDescriptors: [NSSortDescriptor]?,predicate: NSPredicate?) -> NSFetchRequest<Task>
    {
        
        let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
        fetchRequest.includesPendingChanges = false
        fetchRequest.fetchBatchSize = 20
        if sortDescriptors != nil{
            fetchRequest.sortDescriptors = sortDescriptors
        }else{
            fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Task.dateAdded),ascending: false)]
        }
        if predicate != nil{
            fetchRequest.predicate = predicate
        }
        return fetchRequest
    }
}
struct TaskListView: View {
    @StateObject var vm: TaskListViewModel = TaskListViewModel()
    @State var taskToEdit: Task?
    var body: some View {
        if vm.fetchedResultsController?.sections != nil{
            List{
                ForEach(0..<vm.fetchedResultsController!.sections!.count){idx in
                    let section = vm.fetchedResultsController!.sections![idx]

                    TaskListSectionView(objects: section.objects as? [Task] ?? [],taskToEdit: $taskToEdit,sectionName: section.name).environmentObject(vm)
                    
                }
            }.sheet(item: $taskToEdit,onDismiss: {
                vm.save()
            }){editingTask in
                TaskEditView(task: editingTask)
            }
            
        }else{
            Image(systemName: "empty")
        }
    }
}

struct TaskEditView: View {
    @ObservedObject var task: Task
    var body: some View {
        TextField("name",text: $task.name.bound)
    }
}
struct TaskListSectionView: View {
    @EnvironmentObject var vm: TaskListViewModel
    let objects: [Task]
    @State var deleteAlert: Alert = Alert(title: Text("test"))
    @State var presentAlert: Bool = false
    @Binding var taskToEdit: Task?
    var sectionName: String
    
    var body: some View {
        Section(header: Text(sectionName),content: { ForEach(objects,id: \.self){obj in
            let task = obj as Task
            Button(action: {
                taskToEdit = task
            },label: {
                Text(task.name ?? "no name")
            })
            .listRowBackground(Color(UIColor.systemBackground))
            
            
        }.onDelete(perform: deleteItems)
        })
        
    }
    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            deleteAlert = Alert(title: Text("Sure you want to delete?"),primaryButton: Alert.Button.destructive(Text("yes"),action: {
                let objs = offsets.map { objects[$0] }
                
                for obj in objs{
                    
                    vm.deleteObject(object: obj)
                }
                //Because the objects in the sections aren't being directly observed
                vm.objectWillChange.send()
                
            }),secondaryButton: Alert.Button.cancel())
            
            
            self.presentAlert = true
            
        }
    }
}

struct TaskListView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView{
            TaskListView()
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。