NSFetchResultController with UICollectionView issue with indexes / cells when updating and deleting

The first time I use UICollectionView, and I'm having some difficulties. Especially with updating and deleting cells ( NSFetchResultController focus on deleting here, I hope the reason comes), with data from NSFetchResultController . I created a user cell in the inline interface as part of the storyboard:

enter image description here

I have a custom subclass of UICollectionViewCell with the following properties:

 @property (strong, nonatomic) IBOutlet UIButton *deleteButton; @property (strong, nonatomic) IBOutlet UITextField *textField; @property (strong, nonatomic) IBOutlet UIView *containerView; @property (strong, nonatomic) IBOutlet UIView *textFieldContainer; 

In IB, I set the cell class to my custom class, associated the elements with the properties of my custom class, and set the identifier to Cell .

In my View View Collection controller, I configured the collection view and fetchResultController and related methods like this:

 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return [[self.fetchedResultsController sections] count]; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section]; return [sectionInfo numberOfObjects]; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { NoteCollectionViewCell* cell = (NoteCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; [self configureCell:cell atIndexPath:indexPath]; return cell; } - (void)configureCell:(NoteCollectionViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { cell.deleteButton.tag = indexPath.row; [cell.deleteButton addTarget:self action:@selector(deleteNote:) forControlEvents:UIControlEventTouchUpInside]; [...] // I'm having some weird problem with this, se description below. Note *note = [self.fetchedResultsController objectAtIndexPath:indexPath]; cell.textField.tag = indexPath.row; cell.textField.delegate = self; cell.textField.text = note.name; [...] #pragma mark - Fetched results controller - (NSFetchedResultsController *)fetchedResultsController { [Default FRC method] } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { UICollectionView *collectionView = self.collectionView; switch(type) { case NSFetchedResultsChangeInsert: [collectionView insertItemsAtIndexPaths:@[newIndexPath]]; break; case NSFetchedResultsChangeDelete: [collectionView deleteItemsAtIndexPaths:@[indexPath]]; break; case NSFetchedResultsChangeUpdate: [self configureCell:(NoteCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath] atIndexPath:indexPath]; break; } } 

My delete action is as follows:

 - (void)deleteNote:(UIButton *)sender { Note *note = [self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForItem:sender.tag inSection:0]]; [[AppDelegate sharedAppDelegate].managedObjectContext deleteObject:note]; [[AppDelegate sharedAppDelegate] saveContext]; } 

My update action ( UITextField delegate method) is as follows:

 - (void)textFieldDidEndEditing:(UITextField *)textField { Note *note = [self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForItem:textField.tag inSection:0]]; note.name = textField.text; [[AppDelegate sharedAppDelegate] saveContext]; } 

The problem is as follows:

  • The delete button does not always delete the correct cells / object. And sometime the object / cell will not be deleted at all.
  • Sometimes the application crashes when I delete an object (SIGARBT error).
  • Sometimes text appears in the wrong text box.
  • Sometimes, when I delete line 0 with some text, add click "Add", a new cell is added with the same text value as the previous (deleted) cell.

Any ideas on how to solve these problems would be great!

Update

As a comment below, this log in my deleteNote action always returns 0 for the indexPath string. I donโ€™t know if this could be the reason.

 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:sender.tag inSection:0]; NSLog(@"indexPath: %@. Row: %d", indexPath, indexPath.row); 
+1
source share
2 answers

I donโ€™t know if this explains your problem, but you cause

 [cell.deleteButton addTarget:self action:@selector(deleteNote:) forControlEvents:UIControlEventTouchUpInside]; 

every time in configureCell:atIndexPath: so what if the cell is changed or reused. Then call deleteNote: more than once for a one-touch event.

As a workaround, you can check cell.deleteButton.tag to see if the action was already attached to the button or better:

  • add an action to the NoteCollectionViewCell class to a local action in this class when the cell is created,
  • Use delegation to redirect actions to the collection view controller.
+1
source

You cannot associate a selected result controller with a collection view in the same way as a table view. The selected results controller was designed specifically to mediate between master data and the table view, so delegate methods are related to how the table view works.

The main difference is that there are a couple of beginUpdates / endUpdates methods in the beginUpdates endUpdates that you can wrap all updates in. The collection view does not have this, you must create all the required update calls itself, and then, when the handler of the selected results has completed the update, execute all of them in a call to performBatchUpdates:completion:

There is an example implementation of this on GitHub .

+3
source

Source: https://habr.com/ru/post/1496218/


All Articles