0 Replies
      Latest reply on Jun 12, 2019 11:07 PM by raisin
      raisin Level 1 Level 1 (0 points)

        I have been working on this for the last 2 weeks. I have a custom collection view with core data and when I try to insert or delete I get an error and a crash. For inserting data the error is: 'CoreData: fault: Serious application error.  An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.  Invalid update: invalid number of items in section 0.  The number of items contained in an existing section after the update (6) must be equal to the number of items contained in that section before the update (6), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)'

         

        For deleting data the error is: 'CoreData: fault: Serious application error.  An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.  UICollectionView received layout attributes for a cell with an index path that does not exist: <NSIndexPath: 0x600000a5a280> {length = 2, path = 0 - 5} with userInfo (null)'

         

        here is my code:

         

        func numberOfSections(in collectionView: UICollectionView) -> Int {

                return fetchedResultsController.sections!.count

            }

          

            func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

                return fetchedResultsController.sections![section].numberOfObjects

            }

          

          

            func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

              

                let thisAquarium = fetchedResultsController.object(at: indexPath)

              

                let cell: AquariumCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! AquariumCell

              

                cell.picture1.image = UIImage(data: thisAquarium.picture! as Data)

                cell.label1.text = thisAquarium.name!

                cell.label2.text = thisAquarium.location!

              

                if let layout = collectionView.collectionViewLayout as? CollectionViewSlantedLayout {

                    cell.contentView.transform = CGAffineTransform(rotationAngle: layout.slantingAngle)

                }

              

                if (thisAquarium.priority == nil) {

                    let object = "!"

                    DispatchQueue.main.async {

                        thisAquarium.setValue(object, forKey: "priority")

                        ModelManager.instance.saveContext()

                    }

                }

              

                return cell

              

            }

          

            func collectionView(_ collectionView: UICollectionView,

                                layout collectionViewLayout: CollectionViewSlantedLayout,

                                sizeForItemAt indexPath: IndexPath) -> CGFloat {

                return collectionViewLayout.scrollDirection == .vertical ? 275 : 414

            }

          

          

          

          

            func tankFetchRequest () -> NSFetchRequest<Aquarium> {

                let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Aquarium")

                let sortDescriptor = NSSortDescriptor(key: "location", ascending: true)

                let datesortDescriptor = NSSortDescriptor(key: "startDate", ascending: true)

                fetchRequest.sortDescriptors = [sortDescriptor, datesortDescriptor]

                fetchRequest.fetchBatchSize = 30

              

              

                return fetchRequest as! NSFetchRequest<Aquarium>

            }

          

            func getFetchedResultsController() -> NSFetchedResultsController<Aquarium>! {

                fetchedResultsController = NSFetchedResultsController(fetchRequest: tankFetchRequest(), managedObjectContext: ModelManager.instance.managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)

                return fetchedResultsController

            }

          

            func getFetch() {

                fetchedResultsController = getFetchedResultsController()

                fetchedResultsController.delegate = self

                do {

                    try self.fetchedResultsController.performFetch()

                } catch _ {

                    print("Failed to fetch")

                }

            }

          

          

            override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

                if segue.identifier == "DetailAquariumSegue" {

                    let detailVC : DetailTableViewController = segue.destination as! DetailTableViewController

                    let indexPath = self.collectionView.indexPathsForSelectedItems!.last as AnyObject?

                    let thisTank = fetchedResultsController.object(at: indexPath! as! IndexPath)

                    detailVC.detailAquariumModel = thisTank

                }

            }

          

          

            func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {

                blockOperation = BlockOperation()

            }

          

            func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {

              

                switch(type) {

                  

                case .insert:

                    blockOperation.addExecutionBlock {

                        self.collectionView.insertItems(at: [newIndexPath!])

                    }

                  

                case .delete:

                    if let indexPath = indexPath {

                        blockOperation.addExecutionBlock {

                            self.collectionView.deleteItems(at: [indexPath])

                        }

                      

                    }

                  

                case .move:

                    if let indexPath = indexPath {

                        if let newIndexPath = newIndexPath {

                            blockOperation.addExecutionBlock {

                                self.collectionView.deleteItems(at: [indexPath])

                                self.collectionView.insertItems(at: [newIndexPath])

                            }

                          

                        }

                    }

                  

                case .update:

                    if let indexPath = indexPath {

                        blockOperation.addExecutionBlock {

                            self.collectionView.reloadItems(at: [indexPath])

                        }

                      

                    }

                  

                default:

                    break

                  

                }

              

            }

          

            func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {

              

                switch(type) {

                case .insert:

                    blockOperation.addExecutionBlock {

                        self.collectionView.insertSections(IndexSet(integer: sectionIndex))

                    }

                  

                  

                case .delete:

                    blockOperation.addExecutionBlock {

                        self.collectionView.deleteSections(IndexSet(integer: sectionIndex))

                    }

                  

                  

                case .update:

                    blockOperation.addExecutionBlock {

                        self.collectionView.reloadSections(IndexSet(integer: sectionIndex))

                    }

                  

                  

                default:

                    break

                }

            }

          

            func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {

                collectionView.reloadData()

                collectionView.performBatchUpdates({

                    self.blockOperation.start()

                }, completion: { finished in

                    self.blockOperation.cancel()

                  

                })

                collectionView.collectionViewLayout.invalidateLayout()

              

            }

         

         

        As you can see I have tried reloadData() I have tried invalidateLayout(). I can't seem to get anywhere. I don't know if this is a bug in the collectionview and NSfetchedresults controller. I have looked at stackoverflow and have tried multiple things but nothing seems to work.