Я хотел бы иметь список докладчиков (динамиков) в таблице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)
}
}
Не могли бы вы показать нам в дополнение к реализации 'AddSpeakerViewController'? – dasdom
Я только что добавил. Я забыл добавить, что возвращение в topViewController и обратно в SpeakersViewController показывает все динамики правильно, в том числе только что добавленные. –