title: Deleting from UISearchController's filtered search results
body: <p>I have a <code>tableView</code> sourcing its cell content from <code>CoreData</code> and have been replacing the <code>SearchDisplayController</code> (deprecated) with the new <code>SearchController</code>. I am using the same <code>tableView</code> controller to present both the full list of objects and also the filtered/searched objects.</p>
  
  <p>I have managed to get the search/filtering working fine and can move from the filtered list to detail views for those items, then edit and save changes back successfully to the filtered tableView. My problem is swiping to delete cells from the filtered list causes an run time error. Previously with the <code>SearchDisplayController</code> I could do this easily as I had access to the <code>SearchDisplayController's</code> results tableView and so the following (pseudo) code would work fine:</p>
  
  <pre><code>func controllerDidChangeContent(controller: NSFetchedResultsController) {
      // If the search is active do this
            searchDisplayController!.searchResultsTableView.endUpdates()
      // else it isn't active so do this
            tableView.endUpdates()
      }
  }
  </code></pre>
  
  <p>Unfortunately no such tableView is exposed for the <code>UISearchController</code> and Im at a loss. I have tried making the <code>tableView.beginUpdates()</code> and <code>tableView.endUpdates()</code> conditional on tableView not being the search tableView but with no success.</p>
  
  <p>For the record this is my error message:</p>
  
  <p><code>Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.65/UITableView.m:1582</code></p>
  
  <p><strong>* EDIT *</strong></p>
  
  <p>My tableView uses a FetchedResultsController to populate itself from CoreData. This tableViewController also the one used by the SearchController to display filtered results.</p>
  
  <pre><code>var searchController: UISearchController!
  </code></pre>
  
  <p>Then in ViewDidLoad</p>
  
  <pre><code>searchController = UISearchController(searchResultsController: nil)
  searchController.dimsBackgroundDuringPresentation = false
  searchController.searchResultsUpdater = self
  searchController.searchBar.sizeToFit()
  self.tableView.tableHeaderView = searchController?.searchBar
  self.tableView.delegate = self
  self.definesPresentationContext = true
  </code></pre>
  
  <p>and </p>
  
  <pre><code>func updateSearchResultsForSearchController(searchController: UISearchController) {
      let searchText = self.searchController?.searchBar.text
      if let searchText = searchText {
          searchPredicate = searchText.isEmpty ? nil : NSPredicate(format: "locationName contains[c] %@", searchText)
          self.tableView.reloadData()
      }
  }
  </code></pre>
  
  <p>So far as the error message is concerned, I'm not sure how much I can add. The app hangs immediately after pressing the red delete button (Which remains showing) revealed by swiping. This is the thread error log for 1 - 5. The app seems to hang on number 4.</p>
  
  <pre><code>#0  0x00000001042fab8a in objc_exception_throw ()
  #1  0x000000010204b9da in +[NSException raise:format:arguments:] ()
  #2  0x00000001027b14cf in -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] ()
  #3  0x000000010311169a in -[UITableView _endCellAnimationsWithContext:] ()
  #4  0x00000001019b16f3 in iLocations.LocationViewController.controllerDidChangeContent (iLocations.LocationViewController)(ObjectiveC.NSFetchedResultsController) -&gt; () at /Users/neilmckay/Dropbox/Programming/My Projects/iLocations/iLocations/LocationViewController.swift:303
  #5  0x00000001019b178a in @objc iLocations.LocationViewController.controllerDidChangeContent (iLocations.LocationViewController)(ObjectiveC.NSFetchedResultsController) -&gt; () ()
  </code></pre>
  
  <p>I hope some of this helps.</p>
  
  <p><strong>* EDIT 2 *</strong></p>
  
  <pre><code>override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
      if editingStyle == .Delete {
          let location: Location = self.fetchedResultsController.objectAtIndexPath(indexPath) as Location
          location.removePhotoFile()
  
          let context = self.fetchedResultsController.managedObjectContext
          context.deleteObject(location)
  
          var error: NSError? = nil
          if !context.save(&amp;error) {
              abort()
          }
      }
  }
  
  override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
      if self.searchPredicate == nil {
          let sectionInfo = self.fetchedResultsController.sections![section] as NSFetchedResultsSectionInfo
          return sectionInfo.numberOfObjects
      } else {
          let filteredObjects = self.fetchedResultsController.fetchedObjects?.filter() {
              return self.searchPredicate!.evaluateWithObject($0)
          }
          return filteredObjects == nil ? 0 : filteredObjects!.count
      }
  }
  
  // MARK: - NSFetchedResultsController methods
  
  var fetchedResultsController: NSFetchedResultsController {
      if _fetchedResultsController != nil {
          return _fetchedResultsController!
      }
  
      let fetchRequest = NSFetchRequest()
      // Edit the entity name as appropriate.
      let entity = NSEntityDescription.entityForName("Location", inManagedObjectContext: self.managedObjectContext!)
      fetchRequest.entity = entity
  
      // Set the batch size to a suitable number.
      fetchRequest.fetchBatchSize = 20
  
      // Edit the sort key as appropriate.
      if sectionNameKeyPathString1 != nil {
          let sortDescriptor1 = NSSortDescriptor(key: sectionNameKeyPathString1!, ascending: true)
          let sortDescriptor2 = NSSortDescriptor(key: sectionNameKeyPathString2!, ascending: true)
          fetchRequest.sortDescriptors = [sortDescriptor1, sortDescriptor2]
      } else {
          let sortDescriptor = NSSortDescriptor(key: "firstLetter", ascending: true)
          fetchRequest.sortDescriptors = [sortDescriptor]
      }
  
      var sectionNameKeyPath: String
      if sectionNameKeyPathString1 == nil {
          sectionNameKeyPath = "firstLetter"
      } else {
          sectionNameKeyPath = sectionNameKeyPathString1!
      }
  
      // Edit the section name key path and cache name if appropriate.
      // nil for section name key path means "no sections".
      let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: sectionNameKeyPath, cacheName: nil /*"Locations"*/)
      aFetchedResultsController.delegate = self
      _fetchedResultsController = aFetchedResultsController
  
      var error: NSError? = nil
      if !_fetchedResultsController!.performFetch(&amp;error) {
          fatalCoreDataError(error)
      }
  
      return _fetchedResultsController!
  }
  
  var _fetchedResultsController: NSFetchedResultsController? = nil
  
  func controllerWillChangeContent(controller: NSFetchedResultsController) {
      if searchPredicate == nil {
          tableView.beginUpdates()
      } else {
          (searchController.searchResultsUpdater as LocationViewController).tableView.beginUpdates()
      }
  </code></pre>
  
  <p>//        tableView.beginUpdates()
      }</p>
  
  <pre><code>func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
      var tableView = UITableView()
      if searchPredicate == nil {
          tableView = self.tableView
      } else {
          tableView = (searchController.searchResultsUpdater as LocationViewController).tableView
      }
  
      switch type {
      case .Insert:
          tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
      case .Delete:
          tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
      default:
          return
      }
  }
  
  func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath) {
      var tableView = UITableView()
      if searchPredicate == nil {
          tableView = self.tableView
      } else {
          tableView = (searchController.searchResultsUpdater as LocationViewController).tableView
      }
  
      switch type {
      case .Insert:
          println("*** NSFetchedResultsChangeInsert (object)")
          tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
  
      case .Delete:
          println("*** NSFetchedResultsChangeDelete (object)")
              tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
      case .Update:
          println("*** NSFetchedResultsChangeUpdate (object)")
          if searchPredicate == nil {
              let cell = tableView.cellForRowAtIndexPath(indexPath) as LocationCell
              let location = controller.objectAtIndexPath(indexPath) as Location
              cell.configureForLocation(location)
          } else {
              let cell = tableView.cellForRowAtIndexPath(searchIndexPath) as LocationCell
              let location = controller.objectAtIndexPath(searchIndexPath) as Location
              cell.configureForLocation(location)
          }
      case .Move:
          println("*** NSFetchedResultsChangeMove (object)")
          tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
          tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
      }
  }
  
  func controllerDidChangeContent(controller: NSFetchedResultsController) {
      if searchPredicate == nil {
          tableView.endUpdates()
      } else {
          (searchController.searchResultsUpdater as LocationViewController).tableView.endUpdates()
      }
  }
  </code></pre>