Swift UITableView删除选定的行及其上方的任何行

Myc*_*ych 1 uitableview ios swift

我的TableView包含代表里程记录的单元格.我需要允许用户删除任何错误.tableview按降序列出日志.删除顶行是可以的.删除我需要发出警告的任何其他行作为警报,如果确认,则删除所选行+上面的所有行.这可能吗?在任何地方都有代码吗?

UPDATE

根据我迄今为止的两个答案,我已经完成了以下工作....

import UIKit
import CoreData

class MileageLogsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    @IBOutlet var milageLogTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        do {
            try fetchedResultsController.performFetch()
        } catch {
            let fetchError = error as NSError
            print("Unable to fetch MileageLog")
            print("\(fetchError), \(fetchError.localizedDescription)")
        }

        // Display an Edit button in the navigation bar for this view controller.
        self.navigationItem.leftBarButtonItem = self.editButtonItem()
    }

    // MARK: - Table view data source

    private lazy var fetchedResultsController: NSFetchedResultsController = {
        // Initialize Fetch Request
        let fetchRequest = NSFetchRequest(entityName: "MileageLog")

        // Add Sort Descriptors
        let dateSort = NSSortDescriptor(key: "tripDate", ascending: false)
        let mileSort = NSSortDescriptor(key: "startMileage", ascending: false)
        fetchRequest.sortDescriptors = [dateSort, mileSort]

        let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
        let managedObjectContext = delegate.managedObjectContext

        // Initialize Fetched Results Controller
        let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: "rootCache")

        //ADDED AS PER ANSWER FROM SANDEEP
    fetchedResultsController.delegate = self

        return fetchedResultsController

    }()


    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        if let sections = fetchedResultsController.sections {
            return sections.count
        }

        return 0
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let sections = fetchedResultsController.sections {
            let sectionInfo = sections[section]
            return sectionInfo.numberOfObjects
        }

        return 0
    } 

     override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("MileageLogCell") as! MileageTableViewCell

        // Fetch MileageLog
        if let mileageLog = fetchedResultsController.objectAtIndexPath(indexPath) as? MileageLog {
            //format date as medium style date
            let formatter = NSDateFormatter()
            formatter.dateStyle = .MediumStyle
            let logDateString = formatter.stringFromDate(mileageLog.tripDate!)
            //format NSNumber mileage to string
            let mileageInt:NSNumber = mileageLog.startMileage!
            let mileageString = String(mileageInt)

            cell.lb_LogDate.text = logDateString
            cell.lb_LogMileage.text = mileageString
            cell.lb_LogStartLocation.text = mileageLog.startLocation
            cell.lb_LogDestination.text = mileageLog.endLocation
        }
        return cell
     }


    // Override to support conditional editing of the table view.
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return true
    }

    // MARK: Fetched Results Controller Delegate Methods
    func controllerWillChangeContent(fetchedResultsController: NSFetchedResultsController) {
        tableView.beginUpdates()
    }

    func controllerDidChangeContent(fetchedResultsController: NSFetchedResultsController) {
        tableView.endUpdates()
    }

    func controller(fetchedResultsController: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch (type) {
            case .Insert:
                break;
            case .Delete:

                let context = fetchedResultsController.managedObjectContext
                if let indexPath = indexPath {

                    if indexPath.row == 0 {
                        //this is the top (first row)
                        // Deleting without warning
                        let objectToDelete = fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
                        context.deleteObject(objectToDelete)

                        do {
                            try context.save()
                            self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

                        } catch {
                            print(error)
                        }
                        self.tableView.reloadData();

                    } else {
                        //we are deleted a row that is not the top row
                        // we need to give a warning and if acknowledged then delele all rows from the selected row and all rows above it

                        let alertController = UIAlertController(title: nil, message: "Are you sure? This will remove this and all logs above it.", preferredStyle: .Alert)
                        let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in

                        }
                        alertController.addAction(cancelAction)
                        let deleteAction = UIAlertAction(title: "Delete", style: .Default) { (action) in

                            for deleteindex in 0 ... indexPath.row {
                                let deleteIndexPath = NSIndexPath(forRow: deleteindex, inSection: 0)
                                let objectToDelete = self.fetchedResultsController.objectAtIndexPath(deleteIndexPath) as! NSManagedObject
                                context.deleteObject(objectToDelete)

                                do {
                                    try context.save()
                                    self.tableView.deleteRowsAtIndexPaths([deleteIndexPath], withRowAnimation: .Fade)

                                } catch {
                                    print(error)
                                }
                            }
                            self.tableView.reloadData();
                        }
                        alertController.addAction(deleteAction)

                        // Dispatch on the main thread
                        dispatch_async(dispatch_get_main_queue()) { 
                            self.presentViewController(alertController, animated: true, completion:nil)
                        }

                    }
                }
                break;
            case .Update:
                break;
            case .Move:
                break;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

现在我的问题是触摸删除什么也没做.树视图已正确填充."编辑"按钮位于导航栏中.单击编辑,每行显示"无条目"图标...滑动一行,出现删除块.点击删除,没有...... 我错过了什么?

最终工作修正

// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {

    switch editingStyle {

     case .Delete:
        let context = fetchedResultsController.managedObjectContext
            if indexPath.row == 0 {
                //this is the top (first row)
                // Deleting without warning
                let indexPathToDelete = NSIndexPath(forRow: 0, inSection: 0)
                let objectToDelete = fetchedResultsController.objectAtIndexPath(indexPathToDelete) as! NSManagedObject
                context.deleteObject(objectToDelete)

                do {
                    try context.save()
                    //self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

                } catch {
                    print(error)
                }
                //self.tableView.reloadData();

            } else {
                //we are deleted a row that is not the top row
                // we need to give a warning and if acknowledged then delele all rows from the selected row and all rows above it

                let alertController = UIAlertController(title: nil, message: "Are you sure? This will remove this and all logs above it.", preferredStyle: .Alert)
                let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in

                }
                alertController.addAction(cancelAction)
                let deleteAction = UIAlertAction(title: "Delete", style: .Default) { (action) in

                    for deleteindex in 0 ... indexPath.row {
                        let deleteIndexPath = NSIndexPath(forRow: deleteindex, inSection: 0)
                        let objectToDelete = self.fetchedResultsController.objectAtIndexPath(deleteIndexPath) as! NSManagedObject
                        context.deleteObject(objectToDelete)

                    }

                    do {
                        try context.save()

                    } catch {
                        print(error)
                    }
                }
                alertController.addAction(deleteAction)

                // Dispatch on the main thread
                dispatch_async(dispatch_get_main_queue()) {
                    self.presentViewController(alertController, animated: true, completion:nil)
                }

            }
        break;

    default :
        return
    }

}

// MARK: Fetched Results Controller Delegate Methods
func controllerWillChangeContent(controller: NSFetchedResultsController) {
    tableView.beginUpdates()
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    tableView.endUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch type {
    case .Insert:
        break;
    case .Delete:
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
    case .Update:
        break;
    case .Move:
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

vad*_*ian 5

除了使用编辑操作的增强功能外,这是一个简单的解决方案.

首先不要触摸委托方法didChangeObject.
保持原状.它在托管对象上下文中进行更改后调用,并且像MVC模式中的视图一样工作.

 func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch type {
    case .Insert:
      tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
    case .Delete:
      tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
    case .Update:
      self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!)
    case .Move:
      tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
      tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
    }
  }
Run Code Online (Sandbox Code Playgroud)

插入代码以删除commitEditingStyle与MVC模式中的模型类似的行.代码将删除当前部分中上面所选行的所有行.

  override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    switch editingStyle {
    case .Delete:
      let context = fetchedResultsController.managedObjectContext
      let section = indexPath.section
      let currentRow = indexPath.row
      for index in 0...currentRow {
          let indexPathToDelete = NSIndexPath(forRow: index, inSection: section)
          let objectToDelete = fetchedResultsController.objectAtIndexPath(indexPathToDelete) as! NSManagedObject
          context.deleteObject(objectToDelete)
      }
      do {
        try context.save()
      } catch let error as NSError {
        print(error)
      }

    case .Insert, .None: break
    }
  }
Run Code Online (Sandbox Code Playgroud)