Search code examples
iosuitableviewuicollectionviewnsfetchedresultscontroller

How to insert row and section into UICollectionView at same time?


In UITableViewController I can insert row and section at the same time with this implementations:

    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        self.tableView.beginUpdates()
    }

    func controller(controller: NSFetchedResultsController!, didChangeObject anObject: AnyObject!, atIndexPath indexPath: NSIndexPath!, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath!) {

        if controller == frc {

            switch(type) {
            case .Insert:

                self.tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade)

            case .Delete:

                self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

            case .Update:

                self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)

            default:
                break
            }
        }
    }

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {

        switch(type) {
        case .Insert:
            self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        case .Delete:
            self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
        default:
            break
        }
    }

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

What about UICollectionViewController? I haven't found alternative way to implement controllerWillChangeContent and controllerDidChangeContent.


Solution

  • collectionView works somewhat different than tableView, you need to use performBatchUpdates

    var frc: NSFetchedResultsController?
    var iip = [NSIndexPath]()
    var dip = [NSIndexPath]()
    var ins: NSIndexSet?
    var des: NSIndexSet?
    
    func controllerWillChangeContent(controller: NSFetchedResultsController) {
    }
    
    func controller(controller: NSFetchedResultsController!, didChangeObject anObject: AnyObject!, atIndexPath indexPath: NSIndexPath!, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath!) {
    
        if controller == frc {
    
            switch(type) {
            case .Insert:
    
                iip.append(newIndexPath)
    
            case .Delete:
    
                dip.append(indexPath)
    
            case .Update:
    
                self.collectionView!.reloadItemsAtIndexPaths([indexPath])
    
            default:
                break
            }
        }
    }
    
    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
    
        switch(type) {
        case .Insert:
    
            ins = NSIndexSet(index: sectionIndex)
        case .Delete:
    
    
            des = NSIndexSet(index: sectionIndex)
        default:
            break
        }
    }
    
    func controllerDidChangeContent(controller: NSFetchedResultsController) {
    
        self.collectionView!.performBatchUpdates({
    
            self.collectionView!.insertItemsAtIndexPaths(self.iip)
            self.collectionView!.deleteItemsAtIndexPaths(self.dip)
            if self.ins != nil {
                self.collectionView!.insertSections(self.ins!)
            }
            if self.des != nil {
                self.collectionView!.deleteSections(self.des!)
            }
    
            }, completion: {completed in
    
                self.iip.removeAll(keepCapacity: false)
                self.dip.removeAll(keepCapacity: false)
                self.ins = nil
                self.des = nil
        })
    }