UICollectionView insertItemsAtIndexPaths:引发异常 [英] UICollectionView insertItemsAtIndexPaths: throws exception

查看:232
本文介绍了UICollectionView insertItemsAtIndexPaths:引发异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UICollectionView:我做错了.我就是不知道.

UICollectionView: I'm doing it wrong. I just don't know how.

我正在使用iOS 6.0.1的iPhone 4S上运行它.

I'm running this on an iPhone 4S with iOS 6.0.1.

我有一个表格视图,其中一个部分专门用于图像:

I have a table view in which one section is devoted to images:

当用户点击添加图像..."单元格时,系统会提示他们从其图片库中选择一张图像或使用相机拍摄一张新图像.该应用程序的该部分似乎运行正常.

When the user taps the "Add Image..." cell, they are prompted to either choose an image from their photo library or take a new one with the camera. That part of the app seems to be working fine.

当用户第一次添加图像时,将从第二个表格单元格中删除无图像"标签,并以编程方式添加一个UICollectionView.该部分似乎也可以正常工作.

When the user first adds an image, the "No Images" label will be removed from the second table cell, and a UICollectionView, created programmatically, is added in its place. That part also seems to be working fine.

应该在收藏夹"视图中显示它们添加的图像,而这正是我遇到麻烦的地方.(我知道,随着图像数量的增加,我将不得不跳过一些障碍才能使表格视图单元格自身扩大.我还没有那么远.)

The collection view is supposed to display the images they have added, and it's here where I'm running into trouble. (I know that I'm going to have to jump through some hoops to get the table view cell to enlarge itself as the number of images grows. I'm not that far yet.)

当我尝试将一个项目插入集合视图时,它将引发异常.以后再说吧.

When I attempt to insert an item into the collection view, it throws an exception. More on that later.

我由UITableViewController负责表视图,它还充当集合视图的委托和数据源.这是相关的代码(我已经忽略了我认为与该问题无关的控制器的位,包括 -viewDidLoad 之类的方法中的行.自从我删除了大多数图像获取代码后,认为不相关):

I've got the UITableViewController in charge of the table view also acting as the collection view's delegate and datasource. Here is the relevant code (I have omitted the bits of the controller that I consider unrelated to this problem, including lines in methods like -viewDidLoad. I've also omitted most of the image acquisition code since I don't think it's relevant):

#define ATImageThumbnailMaxDimension 100

@interface ATAddEditActivityViewController ()
{
    UICollectionView* imageDisplayView;
    NSMutableArray* imageViews;
}

@property (weak, nonatomic) IBOutlet UITableViewCell *imageDisplayCell;
@property (weak, nonatomic) IBOutlet UILabel *noImagesLabel;
@end

@implementation ATAddEditActivityViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc] init];
    flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;

    imageDisplayView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 290, 120) collectionViewLayout:flowLayout];  // The frame rect still needs tweaking
    imageDisplayView.delegate = self;
    imageDisplayView.dataSource = self;
    imageDisplayView.backgroundColor = [UIColor yellowColor];  // Just so I can see the actual extent of the view
    imageDisplayView.opaque = YES;
    [imageDisplayView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"Cell"];

    imageViews = [NSMutableArray array];
}

#pragma mark - UIImagePickerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    /* ...code defining imageToSave omitted... */

    [self addImage:imageToSave toCollectionView:imageDisplayView];


    [self dismissModalViewControllerAnimated:YES];
}

#pragma mark - UICollectionViewDelegate
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

#pragma mark - UICollectionViewDatasource
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    [[cell  contentView] addSubview:imageViews[indexPath.row]];
    return cell;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return [imageViews count];
}

#pragma mark - UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return ((UIImageView*)imageViews[indexPath.item]).bounds.size;
}

#pragma mark - Image Handling
- (void)addImage:(UIImage*)image toCollectionView:(UICollectionView*)cv
{
    if ([imageViews count] == 0)  {
        [self.noImagesLabel removeFromSuperview];
        [self.imageDisplayCell.contentView addSubview:cv];
    }

    UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
    /* ...code that sets the bounds of the image view omitted... */

    [imageViews addObject:imageView];
    [cv insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:[imageViews count]-1 inSection:0]]];
    [cv reloadData];
}

@end

总结:

  • 通过 -viewDidLoad 方法
  • 实例化并配置收集视图.
  • 接收所选图像的UIImagePickerDelegate方法调用 -addImage:toCollectionView
  • ...这将创建一个新的图像视图来保存图像,并将其添加到数据源数组和集合视图中.这是产生异常的行.
  • UICollectionView数据源方法依赖于imageViews数组.

由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0节中的项目数无效.更新(1)后现有节中包含的项目数必须等于项目数该部分包含在更新之前(1),加上或减去从该部分插入或删除的项目数(已插入1,已删除0),以及加上或减去移入或移出该部分的项目数(移入0),0移出).'

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (1) must be equal to the number of items contained in that section before the update (1), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out).'

如果我正在解析此权限,那么这告诉我的是(全新!)集合视图认为它是由单个项目创建的.因此,我在 -addImage:toCollectionView 中添加了一个日志以测试该理论:

If I'm parsing this right, what this is telling me is that the (brand new!) collection view thinks it was created with a single item. So, I added a log to -addImage:toCollectionView to test this theory:

NSLog(@"%d", [cv numberOfItemsInSection:0]);

在那行中,永远不会引发异常!对 -numberOfItemsInSection:的调用必须强制集合视图查阅其数据源并意识到它没有任何项.或者其他的东西.我在这里猜.但是,好吧,无论如何:收款视图此时仍不显示任何项目,因此我仍然做错了事,我也不知道该怎么办.

With that line in there, the exception never gets thrown! The call to -numberOfItemsInSection: must force the collection view to consult its datasource and realize that it has no items. Or something. I'm conjecturing here. But, well, whatever: the collection view still doesn't display any items at this point, so I'm still doing something wrong and I don't know what.

  1. 当我尝试将项目添加到新创建并插入的集合视图中时,我得到一个奇怪的异常……除非在尝试插入之前我调用 -numberOfItemsInSection:.
  2. >
  3. 即使我设法通过一个可疑的解决方法克服了异常,项目仍不会显示在收藏夹"视图中.

对一个问题的小说感到抱歉.有什么想法吗?

Sorry for the novel of a question. Any ideas?

推荐答案

只是一个猜测:在您插入第一个图像时,收集视图可能尚未加载其数据.但是,在异常消息中,收集视图声称在插入(1)之前知道"项目数.因此,它可能已经懒惰地将其数据加载到 insertItemsAtIndexPaths:中,并将结果视为之前"状态.另外,插入后无需重新加载数据.

Just a guess: at the time you are inserting the first image, the collection view may not yet have loaded its data. However, in the exception message, the collection view claims to "know" the number of items before the insertion (1). Therefore, it could have lazily loaded its data in insertItemsAtIndexPaths: and taken the result as "before" state. Also, you don't need to reload data after an insertion.

长话短说,移动

[cv reloadData];

起床

if ([imageViews count] == 0)  {
    [self.noImagesLabel removeFromSuperview];
    [self.imageDisplayCell.contentView addSubview:cv];
    [cv reloadData];
}

这篇关于UICollectionView insertItemsAtIndexPaths:引发异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆