I am stumped on this. Here is my scenario. In my Appdelegate, I am creating
It is a bug in UICollectionView even in iOS 11, but not exist in UITableView, very easy to reproduce: Assume the following SWIFT code is working:
addItemInDataSource()
collectionView!.insertItems(at: [IndexPath(item: position, section: 0)])
Change it to:
collectionView!.reloadData() // <-- This new line will make UICollection crash...
addItemInDataSource()
collectionView!.insertItems(at: [IndexPath(item: position, section: 0)])
It will crash...
UICollectionView will lose track of the original number of items in some condition, just add a dummy line before insertItems command will avoid this kind of crash:
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)])
Hope it could help in your situation.
I'm not practice with Obj-c so I write my answer in Swift.
supposing birthdays is an array of dates as String
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)] )
}
}
You should avoid this error:
When the collectionview receives the notification I get the error:
'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).'
As the above, to avoid this issue, you can do this:
1. when reload collectionView:
[self.collectionView reloadData];
[self.collectionView layoutIfNeeded];
2. when invoke the batch updates:
[self.collectionView performBatchUpdates:^{
...
[self.dataSource addDataSource:moreDatas];
NSMutableArray *addIndexPaths;
...
if (self.dataSource.count == 1 ||
[self.collectionView numberOfItemsInSection:0] == self.dataSource.count){
[self.collectionView reloadData];
}else{
[self.collectionView insertItemsAtIndexPaths:addIndexPaths];
}
} completion:^(BOOL finished) {}];
As for me the issue was connected to the Index Set - where to insert sections. 1. I've inserted Sections 0..<10 (10 sections) 2. I was trying to insert Sections to IndexSet 9..<19. But appending the new objects to the end of the dataSource array. Correct Index set should be (10..<20)
Thus the last section was still expecting the number of rows from Section 9. But in data source - it was at index 19.
collectionView?.insertSections(IndexSet(integersIn: startIndex..<(startIndex + series.count)))
I had the same error when I've inserted elements in a collectionView with only one section.
I've done the Timothy fix, but it was not enough. In fact, the collectionView had already refreshed its data when I tried to insert new elements. Using collectionView numberOfItemsInSection solves the problem.
[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];
It's a bug with using insertItemsAtIndexPaths
on an empty UICollectionView
. Just do this:
if (self.birthdays.count == 1) {
[self.collectionView reloadData];
} else {
[self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForItem: (self.birthdays.count -1) inSection:0]]];
}
(Can't believe this is still broken in iOS8.)