首页 \ 问答 \ UICollectionView insertItemsAtIndexPaths:抛出异常(UICollectionView insertItemsAtIndexPaths: throws exception)

UICollectionView insertItemsAtIndexPaths:抛出异常(UICollectionView insertItemsAtIndexPaths: throws exception)

UICollectionView:我做错了。 我只是不知道如何。

我的设置

我在带有iOS 6.0.1的iPhone 4S上运行它。

我的目标

我有一个表视图,其中一个部分专门用于图像: 表视图部分的屏幕截图

当用户点击“添加图像...”单元格时,系统会提示他们从照片库中选择图像或使用相机拍摄新照片。 应用程序的这部分似乎工作正常。

当用户首次添加图像时,将从第二个表格单元格中删除“无图像”标签,并在其位置添加以编程方式创建的UICollectionView。 那部分似乎也运作良好。

集合视图应该显示他们添加的图像,它就在我遇到麻烦的地方。 (我知道随着图像数量的增长,我将不得不跳过一些箍来让桌面视图单元扩大。我还没那么远。)

当我尝试将项目插入到集合视图中时,它会抛出异常。 稍后会详细介绍。

我的代码

我有UITableViewController负责表视图也充当集合视图的委托和数据源。 这是相关代码(我省略了我认为与此问题无关的控制器位,包括-viewDidLoad方法中的-viewDidLoad 。我也省略了大部分图像采集代码,因为我认为它不相关) :

#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移动)出)。”

如果我正在解析这个权利,这告诉我的是(全新的!)集合视图认为它是用单个项目创建的。 所以,我添加了一个日志到-addImage:toCollectionView来测试这个理论:

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

随着那条线,这个例外永远不会被抛出! 对-numberOfItemsInSection:的调用-numberOfItemsInSection:必须强制集合视图查询其数据源并意识到它没有项目。 或者其他的东西。 我猜想在这里。 但是,好吧,无论如何:集合视图在这一点上仍然没有显示任何项目,所以我仍然做错了什么,我不知道是什么。

结论是

  1. 当我尝试将一个项目添加到新建和插入的集合视图时,我得到一个奇怪的例外...除非我在尝试插入之前调用-numberOfItemsInSection:
  2. 即使我设法通过阴暗的解决方法超越异常,项目仍然不会显示在集合视图中。

对不起,小问题。 有任何想法吗?


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

My Setup

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

My Goal

I have a table view in which one section is devoted to images: Screen shot of the table view section

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.

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.

My Code

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

To summarize:

  • The collection view is instantiated and configured in the -viewDidLoad method
  • The UIImagePickerDelegate method that receives the chosen image calls -addImage:toCollectionView
  • ...which creates a new image view to hold the image and adds it to the datasource array and collection view. This is the line that produces the exception.
  • The UICollectionView datasource methods rely on the imageViews array.

The Exception

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).'

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]);

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.

In Conclusion

  1. I get an odd exception when I attempt to add an item to a newly-minted-and-inserted collection view...except when I call -numberOfItemsInSection: before attempting insertion.
  2. Even if I manage to get past the exception with a shady workaround, the items still do not show up in the collection view.

Sorry for the novel of a question. Any ideas?


原文:https://stackoverflow.com/questions/13392413
更新时间:2024-05-22 17:05

最满意答案

数据库和应用程序之间没有实时连接。 BindingSource是内存数据缓存和UI之间的链接。 它对数据库一无所知。 LINQ to SQL的工作原理是将数据从数据库中提取到应用程序中。 应用程序必须发起请求。 数据库不会将更改推送到应用程序,因为它不知道可能正在使用该数据的应用程序。 可能存在单个应用程序的单个实例或多个应用程序的数百个用户。


There is no live connection between the database and the application. The BindingSource is a link between the in-memory data cache and the UI. It knows nothing about the database. LINQ to SQL works by pulling data into the application from the database. The application has to initiate the request. The database doesn't push changes to the application because it has no idea what applications there are that may be using that data. There might be a single instance of a single application or hundreds of users of multiple applications.

相关问答

更多

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)