Ios UICollectionView在未高亮显示的项目上崩溃

Ios UICollectionView在未高亮显示的项目上崩溃,ios,objective-c,ios7,uicollectionview,Ios,Objective C,Ios7,Uicollectionview,我收到了一些与iOS 7中的UICollectionView相关的崩溃报告。我无法持续地重现这次崩溃 Exception Type: SIGSEGV Exception Codes: SEGV_ACCERR at 0x91c4392b Crashed Thread: 0 Application Specific Information: *** Terminating app due to uncaught exception '', reason: '' Thread 0 Crashe

我收到了一些与iOS 7中的UICollectionView相关的崩溃报告。我无法持续地重现这次崩溃

Exception Type:  SIGSEGV
Exception Codes: SEGV_ACCERR at 0x91c4392b
Crashed Thread:  0

Application Specific Information:
*** Terminating app due to uncaught exception '', reason: ''

Thread 0 Crashed:
0   libobjc.A.dylib                     0x39dd2b26 objc_msgSend + 6
1   UIKit                               0x31fd5eef -[UICollectionView cellForItemAtIndexPath:] + 111
2   UIKit                               0x32060bfd -[UICollectionView _unhighlightItemAtIndexPath:animated:notifyDelegate:] + 149
3   UIKit                               0x32383947 -[UICollectionView _unhighlightAllItems] + 151
4   UIKit                               0x3205f9fb -[UICollectionView touchesBegan:withEvent:] + 367
5   UIKit                               0x31fcb101 forwardTouchMethod + 233
6   UIKit                               0x31fcb101 forwardTouchMethod + 233
7   UIKit                               0x31e3be4b _UIGestureRecognizerUpdate + 5523
8   UIKit                               0x31e73c41 -[UIWindow _sendGesturesForEvent:] + 773
9   UIKit                               0x31e735e7 -[UIWindow sendEvent:] + 667
10  UIKit                               0x31e48a25 -[UIApplication sendEvent:] + 197
11  UIKit                               0x31e47221 _UIApplicationHandleEventQueue + 7097
12  CoreFoundation                      0x2f69e18b __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
13  CoreFoundation                      0x2f69d6e1 __CFRunLoopDoSources0 + 341
14  CoreFoundation                      0x2f69be4f __CFRunLoopRun + 623
15  CoreFoundation                      0x2f606ce7 CFRunLoopRunSpecific + 523
16  CoreFoundation                      0x2f606acb CFRunLoopRunInMode + 107
17  GraphicsServices                    0x342f4283 GSEventRunModal + 139
18  UIKit                               0x31ea8a41 UIApplicationMain + 1137
19  JackThreadsIpad                     0x000922b7 main (main.m:16)
应用程序中的UICollectionViewCells共享一个管理高亮显示的公共超类。当单元格高亮显示时,alpha会发生变化

- (void)setHighlighted:(BOOL)highlighted {
    [super setHighlighted:highlighted];

    if (highlighted) {
        self.alpha = 0.8;
    } else {
        self.alpha = 1.0;
    }
}
调用[super setHighlighted:highlighted]会导致这样的崩溃吗?该应用程序是使用XCode 4编译和提交的,仅在iOS 7上运行。任何其他的建议,以找出这是发生在哪里。谢谢你的帮助

编辑: 我能够在调试器中捕捉到这一点,但它仍然不能始终重复。坠机原因是:

[NSIndexPath section] message sent to deallocated instance XXXXXXXX

在只识别了这段代码之后,不确定。但由于崩溃信号(SIGSEGV)似乎是由于内存泄漏。您只需转到您的Xcode设置并在内部编辑方案jsut enable Zombie选项,然后尝试重现崩溃。它将向您显示方法的控制器类名或Xcode控制台中与崩溃相关的任何信息。 还可以尝试修改以下条件:-

- (void)setHighlighted:(BOOL)highlighted {

     //just comment this line or write this line to the below and check
     //[super setHighlighted:highlighted];
    if (highlighted) {
        self.alpha = 0.8;
    } else {
        self.alpha = 1.0;
    }
    [super setHighlighted:highlighted];
}

如果在用户拖动视图时调用reloadData,这可能就是原因

我曾经有过类似的崩溃报告,并且通过延迟重载数据调用直到用户完成滚动视图之后,“修复”了这个问题。例如,创建一个包装方法,而不是直接调用重载数据

- (void)updateData {
     if (self.collectionView.isTracking) {
         self.updateDataOnScrollingEnded = YES;
     } else {
         [self.collectionView reloadData];
     }
}
然后,当滚动结束时,从滚动视图的委托方法调用updateData方法(如果需要)

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate) {
        [self scrollViewStopped:scrollView];
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self scrollViewStopped:scrollView];
}

- (void)scrollViewStopped:(UIScrollView *)scrollView
{
    if (self.updateDataOnScrollingEnded) {
         [self updateData];
         self.updateDataOnScrollingEnded = NO;
     }
}
我的猜测是,在collectionView中的某个地方有一个对高亮显示单元格的indexPath的弱引用,调用reload将解除对该indexPath的锁定。当collectionView尝试取消高亮显示单元格时,它会崩溃

编辑:

如下文评论所述,该“解决方案”存在一些缺陷。在进一步研究该问题时,在我的例子中,问题似乎与在拖动集合视图期间在主线程上排队的多个重载数据调用有关。当只有一个重载数据调用时,一切都很好,但当有多个调用时——崩溃

因为我的collectionView中总是只有一个部分,所以我用

reloadSections:[NSIndexSet indexSetWithIndex:0]
但是,这会导致单元格快速淡出并再次淡入,我使用以下方法避免了这种情况(在集合视图中作为一个类别可能会更好)


到目前为止,这对我来说效果很好,它还允许在滚动时实际更新数据。

我遇到了这个问题,尽管有点不同。通过在清除突出显示之前暂停任何重新加载的数据进行修复。虽然toostn的建议可以解决这个问题,但在滚动时重新加载数据是有用的,但在突出显示时没有多大意义,因为你的手指在单元格上

实现以下UICollectionViewDelegate方法:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    self.allowReload = NO;
    return YES;
}


- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    self.allowReload = YES;
    [self reloadIfNecessary]; // calls reloadData if it is necessary to do so!
}

我在集合视图中的
\u unhighlightAllItems
中也发生了此崩溃,在该视图中,我使用了长按识别器来更改单元格的状态(但不是其编号),然后调用
[collectionView reloadData]
。在我的例子中,@toostn(使用
performBatchUpdates
)的解决方案非常有效


我还发现,使用
reloadItemsInstandExpaths:
而不是
reloadData
也可以避免崩溃。

您是否在setHighlighted和cellForItemaIndexPath中添加了断点?在我的开发环境中,我还没有看到过这种崩溃——这种和类似的崩溃报告是通过iTunes Connect和CriterCism发布的。对不起,我错过了你说你不能复制它的那一行。我也看到了这种崩溃,我可以复制它。这似乎与是否覆盖单元格中的setHighlighted,然后在UICollectionView上重复调用reloadData有关,但我仍然没有找到解决方法。在iOS 6中不会发生。得到完全相同的崩溃。在“我的收藏”视图中快速滚动时发生。它似乎与突出显示无关,因为我没有覆盖任何突出显示方法。我认为这解决了问题。。。当集合视图开始跟踪时,它将高亮显示单元格,但当调用reloadData时,即使跟踪停止,高亮显示的状态也会保留。此时,在将来的某个时候,旧的突出显示的索引路径将导致崩溃。不幸的是,对于您的解决方案,跟踪可以在不拖动任何开始的情况下启动和停止,这意味着您永远不会得到任何回调来实际调用重载数据(而且由于拖动的开始通常会取消突出显示单元格,当IsDraging为“是”时,这可能不是一个问题);确保所有委托和数据源方法都准备好接受与旧数据相关的nsindexpath,直到实际调用-reloadData为止。这些当然可以在拖动和滚动期间调用,并且没有-reloadData,collection视图仍将基于以前的数据进行调用。很好!自从我发布了答案后,我发现第二次调用collectionView上的reloadData(在它第一次有机会重新加载数据之前)似乎才是真正的问题。reloadSections方法没有这个问题,因为我开发的应用程序总是有一个部分至少有一个单元格,所以我改为使用reloadSections.Hmmm。我在一个测试应用程序中尝试了这个解决方案和一些变体,我仍然可以使它崩溃,尽管它经常在枚举过程中显示为对集合的变异,而不是释放的对象问题。我不确定一次重新加载如何在其他加载完成之前开始(除非它们在不同的线程上,这将是不好的)。。。它应该是一个同步调用。如果我在重新加载数据之前调用private方法unhighlightAllItems(见上面的回溯),一切都正常,但这不是真正的viab
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    self.allowReload = NO;
    return YES;
}


- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    self.allowReload = YES;
    [self reloadIfNecessary]; // calls reloadData if it is necessary to do so!
}