NSFetchResultController与UICollectionView问题,索引/单元格更新和删除操作

时间:2013-08-10 06:57:11

标签: ios objective-c cocoa-touch uicollectionview nsfetchedresultscontroller

我第一次使用UICollectionView,而且遇到了一些困难。特别是更新和删除单元格(将集中在这里删除,希望是原因),来自NSFetchResultController的数据。我在界面构建器中创建了一个自定义单元格作为故事板的一部分,如下所示:

enter image description here

我有一个自定义UICollectionViewCell子类,其中包含以下属性:

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

在IB中,我将单元类设置为自定义类,将元素连接到自定义类的属性,并将标识符设置为Cell

在我的Collection View视图控制器中,我设置了集合视图和fetchResultController以及类似的相关方法:

- (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;
    }
}

我的删除操作如下所示:

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

我的更新操作(UITextField委托方法)如下所示:

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

问题如下:

  • 删除按钮并不总是删除正确的单元格/对象。有时候根本不会删除对象/单元格。
  • 有时我删除对象时应用程序崩溃(SIGARBT错误)。
  • 有时文本显示在错误的文本字段中。
  • 有时当我删除带有某些文本的第0行时,添加按添加,添加的新单元格与前一个(已删除)单元格的文本值相同。

关于如何解决这些问题的任何想法都会很棒!

更新

如下面的评论,我的deleteNote操作中的此日志始终为indexPath行返回0。不知道那可能是原因。

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

2 个答案:

答案 0 :(得分:4)

您无法将获取的结果控制器链接到集合视图,其方式与表视图完全相同。获取的结果控制器专门用于在核心数据和表视图之间进行调解,因此委托方法与表视图的工作方式相关。

主要区别在于表视图有一个beginUpdates / endUpdates方法对,您可以将所有更新包装在其中。集合视图没有这个,您必须构建自己完成所有必需的更新调用,然后当获取的结果控制器完成更新时,在performBatchUpdates:completion:调用内全部执行它们。

on GitHub有一个示例实现。

答案 1 :(得分:1)

我不知道这是否能解释您的问题,但您致电

[cell.deleteButton addTarget:self action:@selector(deleteNote:)  forControlEvents:UIControlEventTouchUpInside];
configureCell:atIndexPath:中的每次

,以便将多个操作附加到。{1}} 如果单元格被修改或重用,则为按钮。然后调用deleteNote: 一次触摸事件不止一次。

作为一种解决方法,您可以检查cell.deleteButton.tag以查看某个操作是否已附加到该按钮,或更好:

  • NoteCollectionViewCell课程中添加操作 创建单元格时,该类中的本地操作
  • 使用委托将操作转发给集合视图控制器。