2015-04-08 3 views
1

Я хотел бы иметь список докладчиков (динамиков) в таблицеView. Я использую кнопку «edit» в правом верхнем углу таблицыView, чтобы отобразить или скрыть addSpeakerCell в конце всех объектов, которые в настоящее время отображаются. Это работает хорошо и без проблем. Я могу удалить объекты и переключить кнопку редактирования, и все работает так, как предполагается.NSFetchedResultsController с пользовательской ячейкой в ​​Swift

Но при получении в addSpeakerView (через addSpeakerCell) и добавьте динамик, при ударе кнопки сохранить и вернуться к Tableview, появляется следующее предупреждение:

Invalid обновления: недопустимое количество строки в разделе 0. Количество строк, содержащихся в существующем разделе после обновления (1), должно быть равно количеству строк, содержащихся в этом разделе до обновления (0), плюс или минус количество строк, вставленных или удаленных из этот раздел (0 вставлен, 0 удален) и плюс или минус количество строк, перемещенных в или из этого раздела (0 перемещен, 0 выведен). с userInfo (null)

Моя догадка о том, что addSpeakerCell не обновляется с помощью новой indexPath. Но я до сих пор не удалось выяснить, как ее решить ...

Если кто-то любезно указать мне правильное решение или даже предоставить мне необходимый код-сниппет, я был бы бесконечно благодарен

Мой код Tableview:

SpeakersViewController:

class SpeakersViewController: UITableViewController 
    { 
     var managedObjectContext: NSManagedObjectContext! 

     lazy var fetchedResultsController: NSFetchedResultsController = 
     { 
      let fetchRequest = NSFetchRequest() 
      let entity = NSEntityDescription.entityForName("Speaker", inManagedObjectContext: self.managedObjectContext) 
      fetchRequest.entity = entity 
      let sortDescriptor = NSSortDescriptor(key: "firstName", ascending: true) 
      fetchRequest.sortDescriptors = [sortDescriptor] 
      fetchRequest.fetchBatchSize = 20 
      let fetchedResultsController = NSFetchedResultsController(
       fetchRequest: fetchRequest, 
       managedObjectContext: self.managedObjectContext, 
       sectionNameKeyPath: nil, 
       cacheName: "Speaker") 
      fetchedResultsController.delegate = self 
      return fetchedResultsController 
     }() 

     var singleEdit = false // indicates user is swipe-deleting a particular speaker 

     override func viewDidLoad() 
     { 
      super.viewDidLoad() 
      self.navigationItem.rightBarButtonItem = self.editButtonItem() 
      tableView.allowsSelectionDuringEditing = true 

      // CoreData Stuff 
      NSFetchedResultsController.deleteCacheWithName("Speaker") 
      performFetch() 
     } 

     func performFetch() 
     { 
      var error: NSError? 
      if !fetchedResultsController.performFetch(&error) 
      { 
       print("An error occurred: \(error?.localizedDescription)") 
      } 
     } 

     deinit 
     { 
      fetchedResultsController.delegate = nil 
     } 

     override func didReceiveMemoryWarning() 
     { 
      super.didReceiveMemoryWarning() 
     } 

     // Unhide or hide the AddSpeakerCell 
     override func setEditing(editing: Bool, animated: Bool) 
     { 
      super.setEditing(editing, animated: true) 

      if !singleEdit // if user is not swipe-deleting Speaker 
      { 
       self.navigationItem.setHidesBackButton(editing, animated: true) 
      } 

      let sectionInfo = fetchedResultsController.sections![0] as NSFetchedResultsSectionInfo 
      let rows = sectionInfo.numberOfObjects 
      let indexPath = NSIndexPath(forRow: rows, inSection: 0) 
      let indexPaths = [indexPath] 
      if (editing) 
      { 
       tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .Top) 
      } 
      else 
      { 
       tableView.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: .Top) 
      } 
     } 

     // MARK: - Table view data source 
     override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle 
     { 
      let sectionInfo = fetchedResultsController.sections![0] as NSFetchedResultsSectionInfo 
      if indexPath.row == sectionInfo.numberOfObjects 
      { 
       return .Insert 
      } 
      else 
      { 
       return .Delete 
      } 
     } 

     // Unhide or hide the AddSpeakerCell 
     override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
     { 
      let sectionInfo = fetchedResultsController.sections![0] as NSFetchedResultsSectionInfo 
      var rows = sectionInfo.numberOfObjects 
      if (editing) 
      { 
       rows++ 
      } 
      return rows 
     } 

     override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
     { 
      let sectionInfo = fetchedResultsController.sections![0] as NSFetchedResultsSectionInfo 

      if indexPath.row < sectionInfo.numberOfObjects 
      { 
       let cell = tableView.dequeueReusableCellWithIdentifier("SpeakerCell") as SpeakerCell 
       let speaker = fetchedResultsController.objectAtIndexPath(indexPath) as Speaker 
       cell.configureForSpeaker(speaker) 
       return cell 
      } 
      else 
      { 
       let cell = tableView.dequeueReusableCellWithIdentifier("AddSpeakerCell") as UITableViewCell 
       return cell 
      } 
     } 

     override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
     { 
      tableView.deselectRowAtIndexPath(indexPath, animated: true) 
     } 

     override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
     { 
      if editingStyle == .Delete 
      { 
       let speaker = fetchedResultsController.objectAtIndexPath(indexPath) as Speaker 
       managedObjectContext.deleteObject(speaker) 

       var error: NSError? 
       if !managedObjectContext.save(&error) 
       { 
        print("An error occurred: \(error?.localizedDescription)") 
       } 
      } 
     } 

     override func tableView(tableView: UITableView, willBeginEditingRowAtIndexPath indexPath: NSIndexPath) 
     { 
      singleEdit = true 
     } 

     override func tableView(tableView: UITableView, didEndEditingRowAtIndexPath indexPath: NSIndexPath) 
     { 
      singleEdit = false 
     } 

     // MARK: - Navigation 
     override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 
     { 
      if segue.identifier == "AddSpeaker" 
      { 
       let navigationController = segue.destinationViewController as UINavigationController 
       let controller = navigationController.topViewController as AddSpeakerViewController 
       controller.managedObjectContext = managedObjectContext 
      } 
     } 
    } 

    extension SpeakersViewController: NSFetchedResultsControllerDelegate 
    { 
     func controllerWillChangeContent(controller: NSFetchedResultsController) 
     { 
      tableView.beginUpdates() 
     } 

     func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) 
     { 
      if indexPath?.section == 0 
      { 
       switch type 
       { 
       case .Insert: 
        tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) 
       case .Delete: 
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) 
       case .Update: 
        let sectionInfo = fetchedResultsController.sections![0] as NSFetchedResultsSectionInfo 

        if indexPath?.row < sectionInfo.numberOfObjects 
        { 
         let cell = tableView.cellForRowAtIndexPath(indexPath!) as SpeakerCell 
         let speaker = controller.objectAtIndexPath(indexPath!) as Speaker 
         cell.configureForSpeaker(speaker) 
        } 
       case .Move: 
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade) 
        tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade) 
       } 
      } 
     } 

     func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) 
     { 
      if sectionIndex == 0 
      { 
       switch type 
       { 
       case .Insert: 
        tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) 
       case .Delete: 
        tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade) 
       case .Update: 
        break 
       case .Move: 
        break 
       } 
      } 
     } 

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

AddSpeakerViewController:

class AddSpeakerViewController: UITableViewController 
{ 
    var managedObjectContext: NSManagedObjectContext! 

    @IBOutlet weak var speakerFirstNameTextField: UITextField! 
    @IBOutlet weak var speakerLastNameTextField: UITextField! 

    override func viewDidLoad() 
    { 
     super.viewDidLoad() 
    } 
    override func didReceiveMemoryWarning() 
    { 
     super.didReceiveMemoryWarning() 
    } 
    @IBAction func cancelTapped(sender: AnyObject) 
    { 
     dismissViewControllerAnimated(true, completion: nil) 
    } 

    @IBAction func saveTapped(sender: AnyObject) 
    { 
     let speaker = NSEntityDescription.insertNewObjectForEntityForName("Speaker", inManagedObjectContext: managedObjectContext) as Speaker 

     speaker.firstName = speakerFirstNameTextField.text 

     var error: NSError? 
     if !managedObjectContext.save(&error) 
     { 
      println("Error: \(error)") 
      abort() 
     } 
     dismissViewControllerAnimated(true, completion: nil) 
    } 
} 
+0

Не могли бы вы показать нам в дополнение к реализации 'AddSpeakerViewController'? – dasdom

+0

Я только что добавил. Я забыл добавить, что возвращение в topViewController и обратно в SpeakersViewController показывает все динамики правильно, в том числе только что добавленные. –

ответ

0

Ну, после нескольких часов попыток и испытаний и тестирования каждой отдельной строки я наконец выяснил, что вызвало проблему.

Проверка в

controller(didChangeObject) 

для

indexPath?.section == 0 

вызвало проблему. Я действительно не знаю, почему ... Но по крайней мере это работает.

Смежные вопросы