Je suis perplexe à ce sujet. Voici mon scénario. Dans mon Appdelegate, je crée
Voici le code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.evc = [[WTAEntryControllerViewController alloc] init];
WTATableView *tv = [[WTATableView alloc] initWithNibName:@"WTATableView" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:tv];
nav.tabBarItem.title = NSLocalizedString(@"Birthday List", nil);
nav.tabBarItem.image = [UIImage imageNamed:@"birthdaycake"];
WTACollectionViewController *cv = [[WTACollectionViewController alloc]
initWithCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];
[cv.collectionView registerClass:[UICollectionViewCell class]
forCellWithReuseIdentifier:CellIdentifier];
cv.collectionView.backgroundColor = [UIColor whiteColor];
NSLog(@"cv instance %@", cv);
UITabBarController *tabController = [[UITabBarController alloc] init];
tabController.viewControllers = @[nav, cv];
self.window.rootViewController = tabController;
[self.window makeKeyAndVisible];
return YES
}
La vue table a un bouton de barre de navigation qui présente le contrôleur de vue modèle. Le contrôleur de vue modale a un bouton qui prend les valeurs d'un textField et d'un datepicker et les poste dans le centre de notification par défaut avec les valeurs du dictionnaire UserInfo. Le observateur tableView souscrit à la notification, place le dictionnaire UserInfo dans un MutableArray et met à jour la table. Cela fonctionne bien.
Le problème est avec la CollectionVIew. CollectionVIew reçoit la notification et appelle une méthode cible pour gérer la notification. J'essaie de prendre le dictionnaire UserInfo de la notification et d'ajouter une nouvelle cellule à la collectionView.
MAIS...
Lorsque la collectionview reçoit la notification, j'obtiens l'erreur:
'Mise à jour non valide: nombre d'éléments non valide 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'éléments insérés ou supprimés de cette section (1 inséré, 0 supprimé) et plus ou moins le nombre d'éléments entrés dans cette section ou sortis de celle-ci (0 déplacé, 0 déplacé). '
Voici le code pour CollectionView:
#import "WTACollectionViewController.h"
#import "UIColor+WTAExtensions.h"
#import "WTAAppDelegate.h"
#import "WTAEntryControllerViewController.h"
@interface WTACollectionViewController () <UICollectionViewDelegateFlowLayout>
@property (strong, nonatomic) NSMutableArray *birthdays;
@end
@implementation WTACollectionViewController
-(id)initWithCollectionViewLayout:(UICollectionViewLayout *)layout{
NSLog(@"Calling init on Collection");
if(!(self = [super initWithCollectionViewLayout:layout])){
return nil;
}
self.birthdays = [NSMutableArray array];
NSLog(@"Count of Birthdays at init %ld", (long)[self.birthdays count] );
self.title = NSLocalizedString(@"Birthday Grid", nil);
self.tabBarItem.image = [UIImage imageNamed:@"package"];
NSLog(@"cv instance getting notif %@", self);
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleNotification:)
name:@"BirthdayAdded"
object:nil];
return self;
}
-(void)handleNotification:(NSNotification *)notification
{
[self.birthdays addObject:[notification userInfo]];
NSLog(@"Count of birthdays when the notification is received: %ld", (long)
[self.birthdays count]);
[self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:
(self.birthdays.count -1) inSection:0]]];
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"Calling View Did Load on Collection");
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:
(NSInteger)section{
NSLog(@"Count of birthdays in the number of items in section: %ld", (long)
[self.birthdays count]);
return [self.birthdays count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"Calling the cell for index path method");
NSDictionary *dict = [[NSMutableDictionary alloc] init];
dict = self.birthdays[indexPath.item];
UICollectionViewCell *cell = [collectionView
dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
NSAssert(cell != nil, @"Expected a Cell");
cell.contentView.backgroundColor = [UIColor randomColor];
return cell;
}
#define GAP (1.0f)
-(CGSize)collectionView:(UICollectionView *)collectionView layout:
(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath
*)indexPath {
CGFloat edgeLength = self.collectionView.frame.size.width / 4.0f - GAP;
return (CGSize) {.width = edgeLength, .height = edgeLength};
}
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:
(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:
(NSInteger)section{
return GAP;
}
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:
(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:
(NSInteger)section{
return GAP;
}
@end
J'apprécierais tellement quelqu'un qui peut signaler n'importe quoi ici .....
C'est un bug avec l'utilisation de insertItemsAtIndexPaths
sur une UICollectionView
vide. Faites juste ceci:
if (self.birthdays.count == 1) {
[self.collectionView reloadData];
} else {
[self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem: (self.birthdays.count -1) inSection:0]]];
}
(Je ne peux pas croire que cela est toujours cassé dans iOS8.)
C’est un bogue dans UICollectionView même dans iOS 11, mais il n’existe pas dans UITableView, il est très facile à reproduire: Supposons que le code Swift suivant fonctionne:
addItemInDataSource()
collectionView!.insertItems(at: [IndexPath(item: position, section: 0)])
Changez le en:
collectionView!.reloadData() // <-- This new line will make UICollection crash...
addItemInDataSource()
collectionView!.insertItems(at: [IndexPath(item: position, section: 0)])
Il va s'écraser ...
UICollectionView perdra la trace du nombre original d'éléments dans certaines conditions. Il suffit d'ajouter une ligne factice avant que la commande insertItems évite ce type de blocage:
collectionView!.reloadData()
collectionView!.numberOfItems(inSection: 0) //<-- This code is no used, but it will let UICollectionView synchronize number of items, so it will not crash in following code.
addItemInDataSource()
collectionView!.insertItems(at: [IndexPath(item: position, section: 0)])
J'espère que cela pourrait aider dans votre situation.
J'ai eu la même erreur lorsque j'ai inséré des éléments dans une collectionView avec une seule section.
J'ai corrigé Timothy, mais ce n'était pas suffisant. En fait, collectionView avait déjà actualisé ses données lorsque j'ai essayé d'insérer de nouveaux éléments. Utiliser collectionView numberOfItemsInSection résout le problème.
[self.collectionView performBatchUpdates:^{
NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];
for (NSUInteger i = [self.collectionView numberOfItemsInSection:0]; i < self.elements.count ; i++)
{
[arrayWithIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.collectionView insertItemsAtIndexPaths:arrayWithIndexPaths];
} completion:nil];
Dans mon cas, numberOfItemsInSection
a été appelé deux fois à partir de self.performBatchUpdates
(une fois pour le numéro BEFORE, une fois pour le numéro AFTER) parce que j'essayais d'insérer quelque chose dans collectionView avant que le contrôleur de vue ne soit chargé.
La solution consiste à ajouter guard isViewLoaded else { return }
avant d'appeler self.performBatchUpdates
.
Quant à moi, le problème était lié à l'ensemble d'index - où insérer des sections. 1. J'ai inséré les sections 0 .. <10 (10 sections) 2. J'essayais d'insérer des sections dans IndexSet 9 .. <19. Mais en ajoutant les nouveaux objets à la fin du tableau dataSource. L’index correct doit être défini (10 .. <20)
Ainsi, la dernière section s’attendait toujours au nombre de lignes de la section 9. Mais dans la source de données, c’était à l’index 19.
collectionView? .insertSections (IndexSet (integersIn: startIndex .. <(startIndex + series.count)))