NSFetchedResultsController与Swift中的自定义Cell

问题描述 投票:1回答:1

我想在tableView中有一个演示者(发言人)列表。我正在使用tableView右上角的“编辑”按钮取消隐藏或隐藏当前正在显示的所有对象末尾的addSpeakerCell。这很好地工作,没有问题。我可以删除对象并切换编辑按钮,一切都按预期工作。

但是当进入addSpeakerView(通过addSpeakerCell)并添加扬声器时,当按下保存按钮并返回到tableView时,会出现以下警告:

无效更新:第0节中的行数无效。更新(1)后现有部分中包含的行数必须等于更新前的该部分中包含的行数(0),加上或减去数字从该部分插入或删除的行(0插入,0删除)和加或减移入或移出该部分的行数(0移入,0移出)。用户信息(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)
    }
}
ios swift cell nsfetchedresultscontroller
1个回答
0
投票

好吧,经过几个小时的尝试和测试每一行,我终于找到了导致问题的原因。

签到

controller(didChangeObject) 

对于

indexPath?.section == 0

引起了这个问题。我真的不知道为什么......但至少它有效。

© www.soinside.com 2019 - 2024. All rights reserved.