nsfetchedResultsController - 合并数据时出错

时间:2016-04-11 20:16:53

标签: ios swift core-data

我遇到了NSFetchedResultsController的问题。

我有子类FRC

class InboxFetchResultsController: NSFetchedResultsController {

    override init() {
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

        let fetchRequest = NSFetchRequest(entityName: "Compliment")

        let firstSortDescriptor = NSSortDescriptor(key: "updatedAt", ascending: false)
        let secondSortDescriptor = NSSortDescriptor(key: "sendedDate", ascending: false)
        fetchRequest.sortDescriptors = [firstSortDescriptor, secondSortDescriptor]
        let privateManagedObjectContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
        privateManagedObjectContext.parentContext = appDelegate.cdh.managedObjectContext
        let user = try! privateManagedObjectContext.existingObjectWithID(CoreDataManager.sharedInstance.getLoggedUser().objectID) as! User

        let predicate = NSPredicate(format: "recievedBelong = %@", user)

        fetchRequest.predicate = predicate

        super.init(fetchRequest: fetchRequest, managedObjectContext: privateManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
//
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(contextDidSaveContext(_:)), name: NSManagedObjectContextDidSaveNotification, object: nil)
    }


    deinit{
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    func contextDidSaveContext(notification: NSNotification) {
        let sender = notification.object as! NSManagedObjectContext
        if sender != managedObjectContext {
            self.managedObjectContext.performBlock({ [weak self] in
                DDLogInfo("Core data merging")
                self!.managedObjectContext.mergeChangesFromContextDidSaveNotification(notification)
            })

        }
    }

}

使用ComplimentsViewController

lazy var fetchedResultsController: NSFetchedResultsController = {
    let fetchedResultsController = InboxFetchResultsController()
    fetchedResultsController.delegate = self
    fetchedResultsController.fetchRequest.predicate = self.receivedPredicate
    return fetchedResultsController
}()

在viewDidLoad中我正在调用

  func performFetch() {
    fetchedResultsController.managedObjectContext.performBlock { [weak self] in
        do {
            try self!.fetchedResultsController.performFetch()
        } catch {
            let fetchError = error as NSError
            print("\(fetchError), \(fetchError.userInfo)")
        }
        dispatch_async(dispatch_get_main_queue(), {
            self!.tableView.reloadData()
        })
    }

extension ComplimentsViewController: NSFetchedResultsControllerDelegate {
    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        dispatch_async(dispatch_get_main_queue(), {
            self.tableView.beginUpdates()
        })
    }

    func controllerDidChangeContent(controller: NSFetchedResultsController) {
        dispatch_async(dispatch_get_main_queue(), {
            self.tableView.endUpdates()
        })

    }
    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch (type) {
        case .Insert:
            if let indexPath = newIndexPath {
                tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
            }
            break;
        case .Delete:
            if let indexPath = indexPath {
                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
            }
            break;
        case .Update:
            if let indexPath = indexPath {
                tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
            }
            break;
        case .Move:
            if let indexPath = indexPath {
                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
            }

            if let newIndexPath = newIndexPath {
                tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)
            }
            break;
        }
    }

我正在使用在背景上下文中分配的ViewModel在不同的View Controller中编辑获取的对象。 当我保存该背景上下文时,我收到了该错误:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (5) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack:

我花了好几个小时来关注并发性, 几小时检查tableView委托方法...... 仍然会遇到这个问题。

1 个答案:

答案 0 :(得分:1)

您正在使用NSFetchedResultsController,因此您不应该致电:



    dispatch_async(dispatch_get_main_queue(), {
        self!.tableView.reloadData()
    })


由于所有NSFetchedResultsControllerDelegate方法都在这里更新你的tableView,它将自动触发。

此外,您不需要在Swift中使用分号,也不要在break; switch中使用默认行为,除非您明确提及fallthrough