29

我的 UICollectionView 发生了奇怪的崩溃。崩溃的 UICollectionView 嵌入在另一个 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
16 QuartzCore CA::Context::commit_transaction(CA::Transaction*) + 238
17 QuartzCore CA::Transaction::commit() + 316
18 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 60
19 核心基础 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 20
25 UIKit UIApplicationMain + 1120
26 MyApp main.m 第 16 行 main


异常类型:
    EXC_BAD_ACCESS
代码:
    KERN_INVALID_ADDRESS 在 0x158848

我在 setupBSCTopnewsCollectionView 第 52 行所做的是

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

(第 52 行)self.collectionView.collectionViewLayout = 无限布局;



编辑:-[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];
}



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

如果在应用程序运行时重新加载 CollectionView 而不是一开始就在后台,一切都很好。


为了使设置更清晰。

4

4 回答 4

4

首先,在XIB中将一个UICollectionView拖放到您的ViewController,将Delegate,数据源连接到ViewController(这只是主ViewController)

不要为 1 个 CollectionView 使用 2 个不同的 nib 单元,因为您只能注册 1 个 Nib。更好地使用装饰视图作为 HeaderView。创建新类 HeaderView:UICollectionReusableView。这个 UICollectionReusableView 是 UIView 的子类,可以与 UICollectionViewCell 一起在 UICollectionView 内部重用。现在您可以注册两种类型:

[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 中执行此操作,因为您之前 registerNib

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

    [self.topCollectionView setDataSource:self];
    [self.topCollectionView setDelegate:self];
}

它会很好用,如果您将数据源存储在外部,只需创建另一个属性并分配给它,然后在此处用于返回内部数据源。

如果您想知道何时单击 headerView 内的 Cell,请使用 customDelegate 协议在单击 HeaderCell 时将委托发送到 ViewController。

这是我的代码,希望您理解并可以在这里应用您的数据:

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

于 2013-08-22T10:06:44.927 回答
1

看起来您的委托或内部集合视图已死(setWeakDelegatePointer: 做什么?)。在模拟器上尝试僵尸仪器,如果是僵尸,它应该标记。还为 xCode 中的所有异常设置“异常断点”(当应用程序从 xCode 而不是仪器运行时,将有助于您的调试)。还要检查您的-[BSCFrontPageViewController collectionView:cellForItemAtIndexPath:]实现,它可能会在重用时释放该内部集合视图。

编辑:为什么不将标题单元格添加为标题而不是单元格 0(此处为集合视图中的标题示例)?当您为外部集合视图创建普通单元格时,还要检查(只是为了确保它不是崩溃的原因)您的重用标识符。在模拟器上调试时也会定期发送内存警告。

另外,为什么要为标题使用另一个集合视图?您可以使用类似于 iCarousel 的东西来进行这种布局。

于 2013-08-19T05:01:19.683 回答
1

您可以尝试以下操作,滚动主 uicollectionview 以使标题不显示...(更好)然后在模拟器上尝试执行内存警告...使用硬件-> 模拟内存警告...

这可能应该创建一个单元格回收和删除(uicollectionview 应该销毁任何现在不重要的东西......如果发生这种情况,标题将被释放并且你仍然持有对它的弱引用......所以你做的任何事情会因为访问不正确而发生......由于缺乏内存警告(只有您以明确方式创建的警告),这也是“不可能”在模拟器上重现的......

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

于 2013-08-20T22:36:29.960 回答
0

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

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

于 2017-07-06T13:09:33.290 回答