2

我第一次使用 UICollectionView,我遇到了一些困难。尤其是更新和删除单元格(这里将重点关注删除,希望是原因),来自NSFetchResultController. 我在界面生成器中制作了一个自定义单元格,作为故事板的一部分,如下所示:

在此处输入图像描述

我有一个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.

在我的集合视图视图控制器中,我设置了集合视图和 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);
4

2 回答 2

4

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

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

在 GitHub 上有一个示例实现。

于 2013-08-10T07:46:37.343 回答
1

我不知道这是否能解释你的问题,但你打电话

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

每次在 中configureCell:atIndexPath:,以便在修改或重用单元格时将多个操作附加到按钮。然后deleteNote:将多次调用一次触摸事件。

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

  • 创建单元格时,将类中的操作添加到NoteCollectionViewCell该类中的本地操作,
  • 使用委托将操作转发到集合视图控制器。
于 2013-08-10T08:43:14.403 回答