上的访问错误

我在我的UICollectionView中遇到了一个奇怪的崩溃。 崩溃的UICollectionViewembedded在另一个UICollectionView的UICollectionView单元格中。

我不能重现这个问题,它似乎有时如果内部UICollectionView得到新的初始化,因为外面的CollectionView正在重新加载它的单元格。


 com.apple.main-thread崩溃
 0 libobjc.A.dylib objc_msgSend + 9
 1 UIKit  -  [UICollectionViewData _setLayoutAttributes:atGlobalItemIndex:] + 60
 2 UIKit __45- [UICollectionViewData validateLayoutInRect:] _ block_invoke_0 + 668
 3 UIKit  -  [UICollectionViewData validateLayoutInRect:] + 1408
 4 UIKit  -  [UICollectionViewData layoutAttributesForElementsInRect:] + 82
 5 UIKit  -  [UICollectionView setCollectionViewLayout:animated:] + 1644
 6 MyApp BSCTopnewsCollectionView.m第52行 -  [BSCTopnewsCollectionView setupBSCTopnewsCollectionView]
 7 MyApp BSCTopnewsCollectionView.m第27行 -  [BSCTopnewsCollectionView setWeakDelegatePointer:]
 8 Myapp BSCFrontPageViewController.m 550行 -  [BSCFrontPageViewController collectionView:cellForItemAtIndexPath:]
 9 UIKit  -  [UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:] + 252
 10 UIKit  -  [UICollectionView _updateVisibleCellsNow:] + 2672
 11 UIKit  -  [UICollectionView layoutSubviews] + 214
 12 UIKit  -  [UIView(CALayerDelegate)layoutSublayersOfLayer:] + 258
 13 QuartzCore  -  [CALayer layoutSublayers] + 214
 14 QuartzCore CA :: Layer :: layout_if_needed(CA :: Transaction *)+ 460
 15 QuartzCore CA :: Layer :: layout_and_display_if_needed(CA :: Transaction *)+ 16
 QuartzCore CA :: Context :: commit_transaction(CA :: Transaction *)+ 238
 QuartzCore CA :: Transaction :: commit()+ 316
 18 QuartzCore CA :: Transaction :: observer_callback(__ CFRunLoopObserver *,unsigned long,void *)+ 60
 19 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20
 UIKit UIApplicationMain + 1120
 26 MyApp main.m行16主要 


例外types:
     EXC_BAD_ACCESS
码:
     KERN_INVALID_ADDRESS在0x158848 

我在setupBSCTopnewsCollectionView的第52行做的是

 BSCInfiniteLayout * infiniteLayout = [[BSCInfiniteLayout alloc] init];    

 (第52行)self.collectionView.collectionViewLayout = infiniteLayout;


编辑: – [BSCFrontPageViewController collectionView:cellForItemAtIndexPath:]

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { if([collectionView isEqual:self.collectionView]) { if(indexPath.row == 0) // Header Cell { BSCTopnewsCollectionView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:BSCHeaderReuseIdentifier forIndexPath:indexPath]; cell.dataSource = self; cell.weakDelegatePointer = self; self.topNewsCollectionView = cell; return cell; } else { //create normal cells } } else if ([collectionView isEqual:self.topNewsCollectionView.collectionView]) { BSCTopNewsHeaderCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:BSCTopNewsCellReuseIdentifier forIndexPath:indexPath]; BSCNews *topnews = [self.topNews objectAtIndex:indexPath.row]; [cell setEntity:topnews]; return cell; } } 

该方法的一些澄清在那里调用:

 - (void)setWeakDelegatePointer:(BSCFrontPageViewController *)weakDelegatePointer { _weakDelegatePointer = weakDelegatePointer; [self setupBSCTopnewsCollectionView]; [self.collectionView reloadData]; } - (void)setupBSCTopnewsCollectionView { self.collectionView.delegate = self.weakDelegatePointer; self.collectionView.dataSource = self.weakDelegatePointer; BSCInfiniteLayout *infiniteLayout = [[BSCInfiniteLayout alloc] init]; infiniteLayout.delegate = self; // Setup Layout self.collectionView.collectionViewLayout = infiniteLayout; self.collectionView.showsHorizontalScrollIndicator = NO; self.collectionView.pagingEnabled = YES; // Register Cells [self.collectionView registerNib:[UINib nibWithNibName:@"BSCTopNewsHeaderCell" bundle:nil] forCellWithReuseIdentifier:BSCTopNewsCellReuseIdentifier]; } 


编辑3 :崩溃似乎只发生在特殊场合。 如果应用程序在后台,但仍然在内存中,用户再次打开它。 然后检查我们的API是否有新的数据,如果发现有东西会加载它们并重新加载整个外部 collectionView。 那就是当发生崩溃的时候。

如果CollectionView在应用程序运行时重新加载而不在开始的背景中,则一切正常。


为了使设置更清晰一点。

首先,将UICollectionView拖放到XIB中的ViewController中,将Delegate,datasource连接到ViewController(这只是主ViewController)

不要为1个CollectionView使用2个不同的笔尖单元,因为您只能注册1个笔尖。 更好地使用DecorationView作为HeaderView。 创build新的类HeaderView:UICollectionReusableView。 这个UICollectionReusableView是UIView的子类,可以和UICollectionViewCell一起在UICollectionView里面重用。 现在你可以注册这两种types:

 [self.collectionView registerNib:[UINib nibWithNibName:@"MyCell" bundle:nil] forCellWithReuseIdentifier:@"CELL"]; [self.collectionView registerNib:[UINib nibWithNibName:@"HeaderView" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderCell"]; 

接下来,将另一个UICollectionView拖到这个HeaderView中,与HeaderView.h中的IBOutlet连接起来。 在这里,最好将Delegate,DataSource设置为这个类来进行控制。 还要注册这个CollectionView将使用的Nib Cell。 在awakeFromNib中执行,因为你之前注册了Nib

 - (void)awakeFromNib{ [self.topCollectionView registerNib:[UINib nibWithNibName:@"TopCell" bundle:nil] forCellWithReuseIdentifier:@"TopCell"]; [self.topCollectionView setDataSource:self]; [self.topCollectionView setDelegate:self]; } 

如果将数据源存储在外部,只需创build另一个属性并将其分配给数据源,然后在此处使用数据源返回即可。

如果你想知道什么时候点击了headerView中的Cell,使用customDelegate协议在单击HeaderCell时将委托发送到ViewController。

这是我的代码,希望你明白,并可以在这里应用你的数据:

https://github.com/lequysang/gitfiles02/blob/master/CollectionViewWithDecorationView.zip

看起来像你的委托或内部集合视图已经死了(什么setWeakDelegatePointer:做?)。 尝试在模拟器上的僵尸仪器,它应该标志如果僵尸的情况下。 还为xCode中的所有exception设置“Exceptions breakpoint”(将帮助您在从xCode运行应用程序时debugging而不是仪器)。 同时检查你的-[BSCFrontPageViewController collectionView:cellForItemAtIndexPath:]实现,它可能会释放内部收集视图的重用。

编辑:为什么不只是添加标题单元格作为标题,而不是单元格0( 这里集合视图中的标题的例子)? 另外检查(只是为了确保它不是一个崩溃的原因)你的重用标识符,当你创buildg外部收集视图的正常单元格。 在模拟器上进行debugging时,也会定期发送mem警告。

另外,为什么使用另一个集合视图的标题? 你可以使用类似于iCarousel的东西来做这样的布局。

你可以尝试下面的方式,滚动主要uicollectionview所以标题不显示…(进一步更好)然后在模拟器上尝试执行内存警告…使用硬件 – >模拟内存警告…

这应该可能会创build一个单元格回收和删除(uicollectionview应该摧毁任何不重要的东西现在…如果发生这种情况,头将被解除分配,你仍然有一个薄弱的参考…所以你做的任何事情将会发生,因为访问不良…也是由于缺乏内存警告(只有你以明确的方式创build的)在模拟器上重现的“不可能的”..

视图看起来很重,所以你可以尝试这样做,并发布结果?

从评论中拉出我们的“答案”。

可悲的是没有任何答案帮助。 我最终重构了整个事情,然后问题消失了。 我甚至与一位苹果DTS工程师进行了非常详细的交谈,他也不知道该怎么做。 所以我们只是重构。 对不起:/