我希望在tableView中有一个演示者(发言人)列表。我正在使用"编辑"我的tableView右上角的按钮取消隐藏或隐藏当前正在显示的所有对象末尾的addSpeakerCell。这很好地工作,没有问题。我可以删除对象并切换编辑按钮,一切都按预期工作。
但是当进入addSpeakerView(通过addSpeakerCell)并添加一个扬声器时,当点击保存按钮并返回到tableView时,会出现以下警告:
无效更新:第0节中的行数无效。更新(1)后现有部分中包含的行数必须等于更新前的该部分中包含的行数(0),或者减去从该部分插入或删除的行数(0插入,0删除)和加或减移入或移出该部分的行数(0移入,0移出)。 with userInfo(null)
我的猜测是新的indexPath没有更新addSpeakerCell。但后来我仍然无法找到解决方法......
如果有人能够指出我正确的解决方案,或者甚至向我提供必要的代码片段,我会永远感激
我的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 :(得分:0)
好吧,经过几个小时的尝试和测试每一行后,我终于找到了导致问题的原因。
签入
controller(didChangeObject)
代表
indexPath?.section == 0
导致了这个问题。我真的不知道为什么......但至少它有效。