UICollectionView insertItemsAtIndexPaths: throws exception
UICollectionView: je suis en train de faire le mal. Je ne sais juste pas comment.
Ma Configuration
Je suis l'exécution de ce sur un iPhone 4S avec iOS 6.0.1.
Mon Objectif
J'ai une table dans laquelle une section est consacrée aux images:
Lorsque l'utilisateur appuie sur le "Ajouter une Image..." de la cellule, ils sont invités à choisir une image à partir de leur bibliothèque de photos ou de prendre un nouveau avec l'appareil photo. La partie de l'application semble fonctionner correctement.
Lorsque l'utilisateur ajoute une image, le "Pas d'Images" étiquette sera supprimé à partir de la deuxième cellule de tableau, et un UICollectionView, créée par programme, est ajoutée à sa place. La partie semble également fonctionner correctement.
L'affichage de la collection est censé afficher les images qu'ils ont ajouté, et c'est là où je suis en cours d'exécution dans le pétrin. (Je sais que je vais avoir à sauter à travers des cerceaux pour obtenir l'affichage de la table de la cellule pour l'agrandir comme le nombre d'images augmente. Je ne suis pas loin encore.)
Lorsque je tente d'insérer un élément dans la vue de collection, elle lève une exception. Plus sur cela plus tard.
Mon Code
J'ai la UITableViewController en charge de l'affichage de la table en agissant comme l'affichage de la collection du délégué et de la source de données. Voici le code (j'ai omis les bits du contrôleur que je considère comme étrangers à ce problème, y compris les lignes dans les méthodes comme -viewDidLoad
. J'ai aussi omis, en plus de l'acquisition de l'image de code car je ne pense pas que c'est pertinent):
#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
Pour résumer:
- L'affichage de la collection est instancié et configuré dans le
-viewDidLoad
méthode - La UIImagePickerDelegate méthode qui reçoit l'image choisie appels
-addImage:toCollectionView
- ...qui crée une nouvelle image vue de contenir l'image et l'ajoute à la source de données tableau et la vue de collection. C'est la ligne qui produit de l'exception.
- La UICollectionView source de données méthodes reposent sur l'imageViews tableau.
L'Exception
Résiliation d'application en raison de uncaught exception 'NSInternalInconsistencyException', la raison: 'mise à jour incorrecte: non valides nombre d'éléments dans la section 0. Le nombre d'éléments contenus dans une section existante après la mise à jour (1) doit être égal au nombre d'éléments contenus dans cette section avant la mise à jour (1), plus ou moins le nombre d'articles insérés ou supprimés à partir de cette section (1 inséré, 0 supprimés) et plus ou moins le nombre d'éléments déplacés dans cette section (0 déplacé, 0).'
Si je suis d'analyse de ce droit, ce que c'est de me dire, c'est que le (nouveau!) vue de collection pense qu'il a été créé avec un seul élément. Donc, j'ai ajouté un journal à -addImage:toCollectionView
pour tester cette théorie:
NSLog(@"%d", [cv numberOfItemsInSection:0]);
Avec cette ligne là, l'exception n'est jamais jeté! L'appel à -numberOfItemsInSection:
devez forcer l'affichage de la collection de consulter sa source de données et réaliser qu'il n'a pas d'éléments. Ou quelque chose. Je suis conjecturing ici. Mais, bien, que ce soit: l'affichage de la collection n'est toujours pas d'affichage de tous les éléments à ce point, donc je suis encore en train de faire quelque chose de mal et je ne sais pas quoi.
En Conclusion
- J'obtiens une exception lorsque je tente d'ajouter un élément à un nouvellement frappées et inséré vue de collection...sauf quand je l'appelle
-numberOfItemsInSection:
avant de tenter d'insertion. - Même si je parviens à obtenir au-delà de l'exception avec une louche de solution de contournement, les éléments encore, n'apparaissent pas dans l'affichage de la collection.
Désolé pour le roman d'une question. Des idées?
NSLog
déclaration après [imageViews addObject:imageView];
et dans -numberOfItemsInSection
. Qui va vous dire exactement si votre tableau est ce qu'il est censé être et si numberOfItemsInSection
est appelé au bon moment.
OriginalL'auteur Ryan Ballantyne | 2012-11-15
Vous devez vous connecter pour publier un commentaire.
Juste une supposition: au moment de l'insertion de la première image, l'affichage de la collection n'est pas encore chargé de ses données. Toutefois, dans le message d'exception, l'affichage de la collection prétend "savoir" le nombre d'éléments avant de l'insertion (1). Par conséquent, il pourrait avoir langoureusement chargé ses données dans
insertItemsAtIndexPaths:
et pris le résultat comme "avant" de l'état. Aussi, vous n'avez pas besoin de récupérer les données après une insertion.Longue histoire courte, déplacez le
jusqu'à obtenir
Btw, vous n'avez pas besoin d'utiliser
insertItemsAtIndexPaths
à tous. Juste fairereloadData
devrait tout mettre à jour, sans animation.Intéressant. Je me demande quel but cette méthode sert.
De toute façon, il s'avère que mes images n'étaient pas afficher parce que j'ai été appeler setBounds au lieu de setFrame sur mon UIImageViews. En prenant votre suggestion de ne pas l'utiliser insertItemsAtIndexPaths, je suis bon pour aller. Merci!
Le but de insertItemsAtIndexPaths est de minimiser la quantité de travail qui y est accompli, tout en animant le changement. L'appel de reloadData est généralement pas ce que vous voulez faire, car plutôt que de redessiner seulement les cellules affectées, vous forcez le contrôleur de recharger et de re-dessiner tout. Il peut en résulter quelque chose entre un modéré, mais mesurable impact négatif sur votre application, et l'application paralysante, l'INTERFACE utilisateur de gel défaut -- selon le nombre d'éléments de votre collection peut potentiellement avoir.
OriginalL'auteur chris
Malheureusement accepté la réponse est incorrecte (même si c'est sur la bonne voie); le problème, c'est que vous étiez en appelant reloadData & insertItems lorsque vous devriez avoir juste été l'insertion de l'élément. Ainsi, au lieu de:
Viens de faire:
Non seulement cela va vous donner une belle animation, il vous empêche d'utiliser la tableview inefficace (pas une grosse affaire dans une 1-cellule de collecte de vue, mais un énorme problème pour les grands ensembles de données) et d'éviter des accidents comme celui que tu voyais, lorsque les deux méthodes ont été tous les deux en train de modifier l'affichage de la collection (et l'un d'eux -- reloadData -- ne joue pas bien avec les autres).
En aparté, reloadData n'est pas très UICollectionView-amical: si vous avez une importante &/ou complexes de la collection, et une insertion se produit peu de temps avant ou après un appel à reloadData, l'insertion peut se terminer avant la reloadData finitions -- qui sera fiable de cause invalide "nombre d'éléments" crash (en va de même pour les suppressions). L'appel de reloadSections au lieu de simplement reloadData semble pour aider à éviter ce problème.
OriginalL'auteur sounder_michael
Face même de la question, mais la raison avec moi c'est que j'ai oublié de connecter l'affichage de la collection de la Source de Données pour view controller
OriginalL'auteur Mohamed Elkassas
C'est parce que le [nombre de cellules] n'est pas égal à la [index réel count] + [insérer l'index].
Parfois, le dispatch_async ne pas inclure le bloc de la matrice de données d'insertion et insertItemsAtIndexPaths.
J'ai eu le problème avec plusieurs crash. Il n'est pas en cause à chaque fois crash.
OriginalL'auteur zszen