I have a UICollectionView in my iOS application. I'd like to use the various insert... methods to add data, primarily for the animations provided by iOS when using these methods (instead of reloadData:).
If I try to add a section, however, I get an exception from iOS. My code is extremely straightforward:
_regions = [NSMutableArray array];
[self.collectionView reloadData];
NSLog (#"Before attempting to add section, collection view has %ld sections", [self numberOfSectionsInCollectionView:self.collectionView]);
[_regions addObject:#"First Region"];
[self.collectionView insertSections:[[NSIndexSet alloc] initWithIndex:0]];
NSLog (#"After attempting to add section, collection view has %ld sections", [self numberOfSectionsInCollectionView:self.collectionView]);
So I add an object to my _regions array, which I use to implement the data source, then I call insertSection. My first NSLog works:
2015-03-24 11:25:39.052 MyApp[63858:17968323] Before attempting to add section, collection view has 0 sections
but then iOS throws an exception:
2015-03-24 11:25:42.082 MyApp[63858:17968323] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the collection view after the update (1) must be equal to the number of sections contained in the collection view before the update (1), plus or minus the number of sections inserted or deleted (1 inserted, 0 deleted).'
I implement numberOfSectionsInCollectionView in pretty straightforward manner:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return _regions.count;
}
If I reverse the calls (call insertSections before adding the string to the _regions array), I get a different exception:
2015-03-24 11:33:17.472 MyApp[63965:18001840] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert section 0 but there are only 0 sections after the update'
When should I modify (add an element to) _regions, relative to when I add the section to the UICollectionView?
Thanks so much for any help from experienced UICollectionView programmers . . .
Related
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (3) must be equal to the number of sections contained in the table view before the update (3), plus or minus the number of sections inserted or deleted (1 inserted, 0 deleted).'
but i insert 1 and deleted one based on data source what i missed
self.states?.append(sortedStates) //Update state property
if (self.states?.count)! > 3 {
self.states?.removeFirst()
}
self.newsFeedTableView.beginUpdates()
self.newsFeedTableView.insertSections([(self.states?.count)! - 1], with: .none)
if (self.states?.count)! > 3 {
let statesForoldestStateTime = self.states?.first
self.newestStateTime = statesForoldestStateTime?.first?.createdAt
let indexpostion = (self.states?.count)! - 3
self.newsFeedTableView.deleteSections([indexpostion], with: UITableViewRowAnimation.none)
}
self.newsFeedTableView.endUpdates()
The error says it all. When if (self.states?.count)! > 3 is false. The only section would be inserted and not deleted.
You should update your data source accordingly. The number of sections method must return someArray.count. When you insert some section, make sure to update that some array, and when you delete some section, delete the element from some array. That will resolve the issue.
I have UITableView which dataSource change by selecting UISegmentControl's segment. It has only 2 segments and for both states I load data asynchronously first time into 2 different arrays "firstTypeNotificationsArray" and "secondTypeNotificationsArray". The main array is dataSource for UITableVIew which has data from one of arrays each time and it named "allNotificationsArray".
Change main dataSource data method
-(void)changeNotificationsByType:(BOOL)firstType{
[allNotificationsArray removeAllObjects];
if(firstType){
[allNotificationsArray addObjectsFromArray:firstTypeNotificationsArray];
} else {
[allNotificationsArray addObjectsFromArray:secondTypeNotificationsArray];
}
[notificationsTable reloadSections:[NSIndexSet indexSetWithIndex:0]
withRowAnimation:UITableViewRowAnimationFade];
}
Before call method changeNotificationsByType I check my arrays count to be !=0 but I get an NSRangeException after calling.
numberOfRowsInSection method
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return allNotificationsArray.count;
}
I tried to call reloadSections in main thread with dispatch_async but it didn't help. I've also tried to do reloadData instead and no result.
Here is a crash log:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 60 beyond bounds [0 .. 0]'
*** First throw call stack:
(0x265ec87b 0x3832adff 0x26502633 0xfcb9f 0x196879 0x3ee4a5 0x1a9dd17 0x1a9dd03 0x1aa27c9 0x265af555 0x265ada4f 0x26500129 0x264fff1d 0x2fac7af9 0x2a9889bd 0x10cc6d 0x38a78873)
libc++abi.dylib: terminating with uncaught exception of type NSException
This crash raise after switching UISegmentControl and calling changeNotificationsByType respectively. All arrays are not empty at this moment and I can't understand why my app is crashing.
I get an Error:
Assertion failure in -[UICollectionViewData numberOfItemsBeforeSection:],/SourceCache/UIKit_Sim/UIKit-2935.137/UICollectionViewData.m
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for number of items before section 2 when there are only 1 sections in the collection view'
when i try to reload the collectionview.It works when new sections are added but when i try to remove them it throws an exception.
update:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return object.count;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
if([sortString isEqualToString:#"title"])
return [Obj.ordered allKeys].count;
else
return 1;
}
Before deleting rows or sections, you have to delete items from your data source array. If your method returns 1 before deleting section then after deleting it should return 0.
I have searched for this problem and I know it is caused because an array is manipulated while its enumeration. Earlier in my code, I was using :
-(BOOL)busy
{
for(DataRequest* request in self.active)
if(!request.invisible)
return YES;
return NO;
}
and -(BOOL)busy is being called very frequently as the data loads from the server. Also in my code I have some lines which adds and removes objects in self.active. And because of this I was getting the exception. Then I made a change in the code as:
-(BOOL)busy
{
self.tempActive = self.active;
for(DataRequest* request in _tempActive)
if(!request.invisible)
return YES;
return NO;
}
but I am still getting the same exception. What am I doing wrong, any ideas? This is the only code where self.tempActive is used.
The exception I am getting is:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x9ec8f60> was mutated while being enumerated.'
You need to understand the difference between classes and stack objects (like ints and things). Setting something equal to something else does not make a copy of it if it is a class. You need to use [self.active copy] instead.
EDIT - SOLVED: the problem was when I created the string with all the objects to put into the tableview. I used the '?' to separe each object and one of those contained that character so the array broke.
[myString appendFormat:#"%#$%#$%#$%#?",
[currentCampeggioDict valueForKey:#"id"],
[currentCampeggioDict valueForKey:#"nome"], [...]
NS Array *elencoCampeggi=[myString componentsSeparatedByString:#"?"];
That's it.
I have this problem: my app receives from an URL a XML file with a list of objects. The tableview is populated by those objects. There are so many items, so I have to call several times the url, changing a parameter in it for example :
http://www.myurl.com?method=xxx&PAGE=1
http://www.myurl.com?method=xxx&PAGE=2
etc..
The last cell of the tableview contains the sentence "Click to load next 25 objects" and it changes the page number for the URL, delete itself and reload the url, adding the new objects to the tableview.
After 4 times everything works great, but when I press the cell for the fifth, an exception appears with the following text:
Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 17 beyond bounds [0 .. 16]'
Any help? Thanks.
EDIT: some code: this is the part where I delete the last cell
-(void) loadTestData {
// fill moviesArray with test data
NSInteger lastRow = [CampeggiArray count]-1;
if (lastLoadedPage > 1){
[CampeggiArray removeObjectAtIndex:lastRow];
[self.tableView reloadData];
}
[...]
Issue is because you are returning wrong row count in your tableview delegate method. You need to identify the total no of objects to be listed in the tableview and return the count in your tableview delegate method. This is not your page size.
For each hit you need to keep on appending the new objects to the already existing datasource(NSArray) and reload the table.There will be no objects in the datasource during initial hit.
I guess, you are returning 16 instead of 15 in the delegate method, so you wil get crash with exception. Don't hard code values in your delegate method, just get the total number of objects(entire set) and return the count of it.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [totalObjects count];
}