UICollectionView: やり方が間違っています。方法がわかりません。
マイセットアップ
iOS 6.0.1 を搭載した iPhone 4S でこれを実行しています。
私の目標
1 つのセクションが画像専用のテーブル ビューがあります。
ユーザーが [画像を追加...] セルをタップすると、フォト ライブラリから画像を選択するか、カメラで新しい画像を撮影するように求められます。アプリのその部分は正常に動作しているようです。
ユーザーが最初に画像を追加すると、「No Images」ラベルが 2 番目のテーブル セルから削除され、プログラムで作成された UICollectionView がその場所に追加されます。その部分もうまく機能しているようです。
コレクション ビューには、追加された画像が表示されるはずですが、ここで問題が発生します。(画像の数が増えるにつれてテーブルビューのセルを拡大するために、いくつかのフープをジャンプする必要があることはわかっています。まだそこまでではありません。)
コレクション ビューに項目を挿入しようとすると、例外がスローされます。それについては後で詳しく説明します。
マイコード
コレクション ビューのデリゲートおよびデータソースとしても機能するテーブル ビューを担当する UITableViewController を用意しました。関連するコードは次のとおりです (この問題とは無関係と思われるコントローラーのビットを省略しました。たとえば、 のようなメソッドの行も含まれます-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:
挿入を試みる前に呼び出した場合を除きます。 - いかがわしい回避策で例外を回避できたとしても、アイテムはコレクション ビューに表示されません。
質問の小説ですみません。何か案は?