通过 NSNotification 从 UICollectionView 中删除单元格

Posted

技术标签:

【中文标题】通过 NSNotification 从 UICollectionView 中删除单元格【英文标题】:Deleting cells from UICollectionView via NSNotification 【发布时间】:2012-10-15 10:58:01 【问题描述】:

为了简单起见,我有一个基于 UICollectionView 的简单应用程序 - 一个 UICollectionView 和一个基于 NSMutableArray 的数据模型。

我可以通过 didSelectItemAtIndexPath: 委托方法毫无问题地删除单元格:

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
    [self.data removeObjectAtIndex:[indexPath row]];
    [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];

但是,我正在尝试通过UICollectionViewCell 子类中的UIMenuController 添加删除选项,该子类通过UILongPressGestureRecognizer 触发,一切正常,我成功触发NSNotification

-(void)delete:(id)sender
      NSLog(@"Sending deleteme message");
      [[NSNotificationCenter defaultCenter] postNotificationName:@"DeleteMe!" object:self userInfo:nil];

我在 ViewController 中捕获它并调用以下方法:

-(void)deleteCell:(NSNotification*)note
       MyCollectionViewCell *cell = [note object];
       NSIndexPath *path = nil;
       if((path = [self.collectionView indexPathForCell:cell]) != nil)
           [self.data removeObjectAtIndex:[path row]];
           [self.collectionView deleteItemsAtIndexPaths:@[path]];
       

它在 deleteItemsAtIndexPaths 上崩溃:调用

-[UICollectionViewUpdateItem action]: unrecognized selector sent to instance 0xee7eb10

我已经检查了所有明显的东西——比如来自 NSNotification 的对象和从 indexPathForCell: 调用创建的 indexPath,这一切看起来都很好。似乎我在两个地方都使用相同的信息调用 deleteItemsAtIndexPath:,但由于某种原因,它在通过通知路由时失败了。

这是错误中给出的地址的信息:

(lldb) po 0xee7eb10
(int) $1 = 250080016 <UICollectionViewUpdateItem: 0xee7eb10> index path before update (<NSIndexPath 0x9283a20> 2 indexes [0, 0]) index path after update ((null)) action (delete)

也许更新为空后的索引路径很重要……

有什么想法吗?

【问题讨论】:

deleteCell: 你使用self.collectionViewOneself.collectionView - 这是故意的吗? 我可以确认从通知中插入新项目时也会发生这种情况。 我也遇到了同样的问题,恐怕是UIMenuController引起的!当我在 UICollectionViewCell 中嵌入 UITextView 时,如果长按 UITextView 以显示系统默认菜单,则会收到警告:“[UICollectionViewUpdateItem action]: unrecognized selector sent to instance”,如果插入项目,则与您的错误相同。 好的,所以原因似乎是 UICollectionViewCell 内容视图中的 UITextView 本身。不知道它是否相关,但使用 UITextView 创建单元格时的第一个警告是:“设置集合视图的第一响应者视图,但我们不知道它的类型(单元格/页眉/页脚)”。随后尝试在集合视图中插入/删除项目会导致崩溃。就我而言,这只是发生在通知块内的巧合。 @melps 你的 MyCollectionViewCell 类是否包含 UITextView? 认为我已经确定了问题所在,在我的情况下,当键盘显示时尝试在集合视图中插入/删除项目时会发生异常。在插入/删除之前先关闭键盘似乎可以解决问题 【参考方案1】:

我找到了一个粗略但可行的解决方法,它甚至会检查是否已经在未来的版本中实施了操作(比类别更好)

// Fixes the missing action method when the keyboard is visible
#import <objc/runtime.h>
#import <objc/message.h>
__attribute__((constructor)) static void PSPDFFixCollectionViewUpdateItemWhenKeyboardIsDisplayed(void) 
    @autoreleasepool 
    if ([UICollectionViewUpdateItem class] == nil) return; // pre-ios6.
    if (![UICollectionViewUpdateItem instancesRespondToSelector:@selector(action)]) 
            IMP updateIMP = imp_implementationWithBlock(^(id _self) );
            Method method = class_getInstanceMethod([UICollectionViewUpdateItem class], @selector(action));
            const char *encoding = method_getTypeEncoding(method);
            if (!class_addMethod([UICollectionViewUpdateItem class], @selector(action), updateIMP, encoding)) 
                NSLog(@"Failed to add action: workaround");
            
        
    

编辑:添加了对 iOS5 的检查。 编辑 2:我们在许多商业项目 (http://pspdfkit.com) 中提供了它,效果很好。

【讨论】:

这个答案对我来说就像一个魅力。应标记为解决方案。 谢谢,为我工作。顺便说一句,当我在单元格内设置一个视图作为第一响应者时,我得到了,并且没有可见的键盘 有人有一个最小的例子说明是什么原因造成的吗?我在另一个应用程序中遇到崩溃,没有显示键盘或更改第一响应者。 这似乎真的有效。在测试版本中使用它,崩溃就消失了。然而,似乎有一些奇怪的东西,其中“仍然存在”但在滚动区域之外的单元格。就好像崩溃应该出现时它们根本没有被删除一样。但是,我可以忍受它。【参考方案2】:

您可以在通知的userInfo 字典中传入所选单元格的NSIndexPath。您可以在创建自定义单元格时将其设置在自定义单元格的 tag 中。

【讨论】:

但这不是 NSIndexPath 错误的问题,所以我不确定这会有什么帮助。【参考方案3】:

我遇到了同样的问题。当我在 UITextField 中选择文本后尝试将单元格插入到 UICollectionView 中时,我的应用程序会崩溃,该文本位于 collectionViewCell 内。我的解决方法是在插入发生之前辞去第一响应者的职务。因为我使用NSFetchedResultsController 来处理更新,所以我把它放在controllerWillChangeContent: 的开头

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
    [[UIApplication sharedApplication].keyWindow findAndResignFirstResponder];
    ...

我找到了findAndResignFirstResponderfrom this SO answer

【讨论】:

以上是关于通过 NSNotification 从 UICollectionView 中删除单元格的主要内容,如果未能解决你的问题,请参考以下文章

键入“NSNotification.Name?”没有成员“firInstanceIDTokenRefresh”

NSNotification 检测其他程序的崩溃

04 KVC|KVO|Delegate|NSNotification区别

Swift 中多个 UIViewContoller 中的 NSNotification 处理

iOS开发中NSNotification的便利使用

iOS开发中NSNotification的便利使用