title: Swift UITableView delete selected row and any rows above it
body: <p>My TableView contains cells that represent a mileage log. I need to allow users that ability to delete any mistakes. The tableview lists the logs in descending order. Deleting the top row is OK. Deleting any other row I need to issue a warning as an alert and if confirmed then delete the selected row + all rows above it. Is this possible? Is there any example code anywhere? </p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Based on the two answers I have had so far I have done the following....</p>
  
  <pre><code>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) -&gt; Int {
          if let sections = fetchedResultsController.sections {
              return sections.count
          }
  
          return 0
      }
  
      override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
          if let sections = fetchedResultsController.sections {
              let sectionInfo = sections[section]
              return sectionInfo.numberOfObjects
          }
  
          return 0
      } 
  
       override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -&gt; 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) -&gt; 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;
          }
      }
  
  }
  </code></pre>
  
  <p>Now my problem is that the touching Delete does nothing. The treeview is correctly populated. The Edit button is in the navbar. Click Edit and the 'no entry' icon appear on each row... slide a row and the Delete block appears. Click delete and nothing...! What have I missed out?</p>
  
  <p><strong>FINAL WORKING FIX</strong></p>
  
  <pre><code>// 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;
      }
  }
  </code></pre>