it-swarm.com.de

Ungültiges Update: ungültige Anzahl von Elementen in UICollectionView

Ich bin darüber überrascht. Hier ist mein Szenario. In meiner Appdelegate schaffe ich

  1. Eine Instanz eines View-Controllers, die modal dargestellt wird, um zwei Daten vom Benutzer zu erfassen
  2. Ein TableView-Controller
  3. Ein Navigationscontroller, den ich mit dem Tableview-Controller als Rootview initiiere
    Regler
  4. Ein collectionviewController, beachte, dass ich hier auch die Klasse für die Zelle registriere. 
  5. Ein UITabBarController, den ich als ersten View und den
    collectionview als zweite Ansicht. Der TabBarCOntorller wird als Rootview des Fensters festgelegt. 

Hier ist der 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
}

Die TableView verfügt über eine Navbar-Schaltfläche, mit der der Controller für die Modellansicht angezeigt wird. Der Controller für modale Ansichten verfügt über eine Schaltfläche, die die Werte aus einem textField und einem Datepicker übernimmt und diese mit den Werten im UserInfo-Wörterbuch an das Standardbenachrichtigungscenter sendet. Der tableView-Contorller abonniert die Benachrichtigung, ordnet das UserInfo-Wörterbuch in einem MutableArray an und aktualisiert die Tabelle. Das funktioniert gut. 

Das Problem liegt bei der CollectionVIew. Die collectionVIew empfängt die Benachrichtigung und ruft eine Zielmethode zur Verarbeitung der Benachrichtigung auf. Ich versuche, das UserInfo-Wörterbuch aus der Benachrichtigung zu entnehmen und der collectionView eine neue Zelle hinzuzufügen. 

ABER...

Wenn die Sammlungsansicht die Benachrichtigung erhält, erhalte ich die Fehlermeldung: 

'Ungültige Aktualisierung: Ungültige Anzahl von Elementen in Abschnitt 0. Die Anzahl der Elemente, die in einem vorhandenen Abschnitt nach der Aktualisierung (1) enthalten sind, muss der Anzahl der Elemente in diesem Abschnitt vor der Aktualisierung (1) entsprechen, plus oder minus Anzahl der Elemente, die in diesem Abschnitt eingefügt oder aus dieser entfernt wurden (1 eingefügt, 0 gelöscht) und plus oder minus der Anzahl der Elemente, die in diesen Abschnitt verschoben oder aus diesem Abschnitt verschoben wurden (0 verschoben, 0 ausgezogen). "

Hier ist der Code für die 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

Ich würde jeden so sehr schätzen, der hier auf etwas hinweisen kann .....

30
Tommy Alexander

Es ist ein Fehler bei der Verwendung von insertItemsAtIndexPaths für eine leere UICollectionView. Mach einfach das:

if (self.birthdays.count == 1) {
    [self.collectionView reloadData];
} else {
    [self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:   (self.birthdays.count -1) inSection:0]]];
}

(Ich kann nicht glauben, dass dies in iOS8 immer noch kaputt ist.)

57
Timothy Moose

Es ist ein Fehler in UICollectionView, auch in iOS 11, aber in UITableView nicht vorhanden, sehr einfach zu reproduzieren:. 

addItemInDataSource()
collectionView!.insertItems(at: [IndexPath(item: position, section: 0)])

Ändern Sie es in:

collectionView!.reloadData()    // <-- This new line will make UICollection crash...

addItemInDataSource()
collectionView!.insertItems(at: [IndexPath(item: position, section: 0)])

Es wird abstürzen ...

UICollectionView verliert unter bestimmten Bedingungen die ursprüngliche Anzahl der Elemente. Fügen Sie einfach eine Dummy-Zeile hinzu, bevor der Befehl insertItems diese Art von Absturz verhindert:

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

Ich hoffe, es könnte in Ihrer Situation helfen.

19
Michael Su

Ich hatte den gleichen Fehler, wenn ich Elemente mit nur einem Abschnitt in eine collectionView eingefügt habe. 

Ich habe den Timothy-Fix ​​gemacht, aber es hat nicht gereicht. Tatsächlich hatte das collectionView bereits seine Daten aktualisiert, als ich versuchte, neue Elemente einzufügen. Mit collectionView numberOfItemsInSection wird das Problem gelöst. 

[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];
12
vmeyer

In meinem Fall wurde numberOfItemsInSection zweimal von self.performBatchUpdates aufgerufen (einmal für die VOR-Nummer, einmal für die NACH-Nummer), da ich vor dem Laden des View-Controllers etwas in die collectionView einfügen wollte.

Die Lösung besteht darin, guard isViewLoaded else { return } vor dem Aufruf von self.performBatchUpdates hinzuzufügen.

3
p-sun

Für mich war das Problem mit dem Index-Set verbunden, an dem Abschnitte eingefügt werden. 1. Ich habe die Abschnitte 0 .. <10 (10 Abschnitte) .__ eingefügt. 2. Ich habe versucht, Sections in IndexSet 9 einzufügen. <19. Die neuen Objekte werden jedoch an das Ende des dataSource-Arrays angehängt. Der korrekte Indexsatz sollte (10 .. <20) sein.

Daher erwartete der letzte Abschnitt immer noch die Anzahl der Zeilen aus Abschnitt 9. Aber in der Datenquelle - es war Index 19. 

collectionView? .insertSections (IndexSet (integersIn: startIndex .. <(startIndex + series.count)))

0
Naloiko Eugene

Ich übe nicht mit Obj-c, also schreibe ich meine Antwort in Swift.

angenommen, Geburtstage sind eine Reihe von Daten als Zeichenfolge

birthdays = [String]()

func addDate() {
   birthdays.append("your_new_date")
   collectionView.insertItems(at: [IndexPath(item: birthdays.count - 1, section: 0)] ) 
}

func removeDate() {
   if birthdays.count > 0 {
      birthdays.removeLast() // use remove(at: Int) instead if u want
      collectionView.deleteItems(at: [IndexPath(item: birthdays.count, section: 0)] )
   }
}

Sie sollten diesen Fehler vermeiden:

Wenn die Sammlungsansicht die Benachrichtigung erhält, erhalte ich die Fehlermeldung:

'Ungültige Aktualisierung: Ungültige Anzahl von Elementen in Abschnitt 0. Die Anzahl der Elemente in einem vorhandenen Abschnitt nach der Aktualisierung (1) muss der Anzahl der Elemente in diesem Abschnitt vor der Aktualisierung (1) plus oder minus dem entsprechen Anzahl der Elemente, die in diesem Abschnitt eingefügt oder gelöscht wurden (1 eingefügt, 0 gelöscht) und plus oder minus der Anzahl der Elemente, die in diesen Abschnitt verschoben oder daraus entfernt wurden (0 eingezogen, 0 ausgezogen). “

0