通过 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.collectionViewOne
和self.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];
...
我找到了findAndResignFirstResponder
from this SO answer
【讨论】:
以上是关于通过 NSNotification 从 UICollectionView 中删除单元格的主要内容,如果未能解决你的问题,请参考以下文章
键入“NSNotification.Name?”没有成员“firInstanceIDTokenRefresh”
04 KVC|KVO|Delegate|NSNotification区别