Adding an object before the current index in UICollectionView - ios

I have a simple collection view that has two types of cells. A counter cell, and an "add" cell. My goal is to have the "add" cell remain at the end of the index after new objects are added. When I run the application my "add" cell appears but I get an error when the "add" button is pressed.
Here is the error:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: '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).'
And here is my code:
// retrievedCounters is an NSMutableDictionary
- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
// only want one section
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
// get the current count and add one for the "add" cell
return retrievedCounters.count + 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell;
// check whether the index path is at the very end and add the appropriate cell
if (indexPath.row == retrievedCounters.count) {
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"AddCounter" forIndexPath:indexPath];
}
else {
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CounterCell" forIndexPath:indexPath];
}
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
// insert new counter at index path
[self.collectionView insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:retrievedCounters.count-1 inSection:0]]];
}
Thank you to anyone who can help!

The error indicates a data source issue when changing your datasource. The number of your keys in the mutable dictionary is not correct.
Presumably you are using the NSIndexPaths as keys and the data you need as values. I would think it easier to use an array instead (indexPath.row would then simply point to the right object in the right order).
Check your update method where you change the data in the datasource. You should ensure that your dictionary contains the expected number of items.
In your error message, the 1 item before and after the insert seems to indicate that maybe your dictionary became nil and therefore returns a zero count. Ensure that you have a properly instantiated instance variable.

In your objects array whenever you add new objects
create new array for new objects and than add it like this
[existingArray addObjectsFromArray:newarray];
the sequence would be maintained

Related

swipe to delete uitableview cell [duplicate]

This question already has answers here:
'Invalid update: invalid number of rows in section 0
(4 answers)
Closed 6 years ago.
emphasized textreason:
Invalid update: invalid number of rows in section 0.
The number of rows contained in an existing section after
the update (5) must be equal to the number of rows contained in
that section before the update (5), plus or minus the number of
rows inserted or deleted from that section (0 inserted, 1 deleted)
and plus or minus the number of rows moved into or out of that
section (0 moved in, 0 moved out).
*** First throw call stack
I got this error when I'm trying to delete
This error means that when you update the UITableView after the deletion, the array that you are using as your Data Source has not been updated.
In other words:
You have the NSArray dataArray that you are using in cellForRowAtIndexPath in your UITableViewDelegate.
You animate the cell to delete the row, but then you never call
[dataArray removeObjectAtIndex:index];
So when the table renders again, the UITableView expects there to be 5 items, but your array still has 6.
your question is unclear , follow these steps
in delegate method commitEditingStyle, delete object from array.
then apply deleterow animation on table with updated array.
i think u r not deleting object from your collection i.e array
try this code.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableDataArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
For More reference You can visit here

Inserting a New Cell Into A UICollectionView

I’m trying to add in a new cell into my collection view, only if it has more than one item already in it. I have no worked much with collection views, and research in the docs and this site had not helped solve this issue yet. So, on my cellForItemAtIndexPath method, I do a check to see if it is populated. If not, I add the cell, like so:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if (self.myArray.count != 0) {
return self.myArray.count + 1;
}
else {
return self.myArray.count;
}
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyNormalCollectionViewCellS *cells = (MyNormalCollectionViewCells *) [collectionView dequeueReusableCellWithReuseIdentifier:#"MyNormalCollectionViewCells” forIndexPath:indexPath];
cell.clipsToBounds = NO;
DataClass *data = [self.myArray objectAtIndex:indexPath.row];
[cells configureMyNormalCellsWith:data];
if (0 < self.myArray.count) {
UICollectionViewCell *deleteCell = [UICollectionViewCell new];
deleteCell.backgroundColor = [UIColor yellowColor];
NSArray *newData = [[NSArray alloc] initWithObjects:deleteCell, nil];
[self.myArray addObjectsFromArray:newData];
NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];
[self.myCollectionView insertItemsAtIndexPaths:arrayWithIndexPaths];
return deleteCell;
}
return cell;
}
For some reason, I have an assertion being thrown, stating:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of items in section 0. The number of items contained in an
existing section after the update (7) must be equal to the number of
items contained in that section before the update (6), plus or minus
the number of items inserted or deleted from that section (0 inserted,
0 deleted) and plus or minus the number of items moved into or out of
that section (0 moved in, 0 moved out).'
Of course, the number usually varies, but it's always angry about that extra cell. Everything is fine up until I try and add it in. Now, being unfamiliar with collection views and after browsing related questions upon this site, I decided it was time to ask the pros.
Does anyone know how I should change this code in order to accomplish what I'm trying to do?
Don't modify data source in collectionView:cellForItemAtIndexPath:. Return different number of items in - collectionView:numberOfItemsInSection: instead:
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section {
if (self.dataArray.count > 0) {
return self.dataArray.count + 1;
}
else {
return 0;
}
}
In collectionView:cellForItemAtIndexPath: you should return your "normal" cell for "normal" item, and "extra" cell for that extra one, depending on the value of indexPath.row. For example:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row < self.dataArray.count) { // if indexPath.row is within data array bounds
// dequeue, setup and return "normal" cell
} else { // this is your "+1" cell
// dequeue, setup and return "extra" cell
}
}

Deleting an NSManagedObject from a managedObjectContext

I have a UITableViewController set up that displays my managedObjects properly when it's loaded, however when I go to delete a cell my app crashes. This is what the console has to say:
2015-05-03 09:55:20.125 MyApp[9461:663817] *** Terminating app due to
uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update:
invalid number of rows in section 0. The number of rows contained in an existing
section after the update (1) must be equal to the number of rows contained in
that section before the update (1), plus or minus the number of rows inserted or
deleted from that section (0 inserted, 1 deleted) and plus or minus the number of
rows moved into or out of that section (0 moved in, 0 moved out).'
When I reboot the app and go to my TVC, the object that I deleted the last time is deleted.
I have sections set up in my NSFetchedResultsController that is instantiated when viewDidLoad is called. I suspect I have a small issue, but I'm not sure where to go to add the missing line(s?).
I enable swipe to delete in viewDidLoad with this line:
// Enable swipe to delete
self.tableView.allowsMultipleSelectionDuringEditing = NO;
Here's my commitEditingStyle:
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete selected NSManagedObject from managedObjectContext
NSManagedObject *objectToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:objectToDelete];
[self.managedObjectContext save:nil];
// Delete the row from the data source
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
Thank you for reading. If you have any ideas, I welcome them.
The error message is saying that number of row returns from numberOfRowInSection is not matching with current number of item in table..
when you use fetchedResultsController numberOfRowsInSection should look something like this.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.fetchedResultsController fetchedObjects] count];
}
and fetchedResultsController delegate didChangeObject: is then called automatically which calls the deleteRowAtIndexPaths: inside.. so you don't need to call the deleteRowAtIndexPaths: just call deleteObject, otherwise it deletes twice.

Add new items to UITableView without replacing old items

I intended to add items to a UITableView when this method was called. New items are successfully added (but there's a problem, mentioned below), but I think its odd because I thought "begin updates" to "end updates" was supposed to handle this (Inserting a new row). The initial if condition I had put in never ran so the whole area never got executed. I only realized this recently and updated the condition to what it is now. Now the if block get executed and it crashes the app.
When it is commented out like it is now... New items are added but the newNameOfItem replaces any existing cell labels.
I would like this to add x(newNumberOfItems) new items preferably into a new section each time its called. How can I achieve this?
- (void)addNew:(NSString *)newNumberOfItems :(NSString *)newNameOfItem
{
if(!self.numberOfRows){
NSLog(#"Initially no of rows = %d", self.numberOfRows);
self.numberOfRows = [self.numberOfItems intValue];
NSLog(#"Then no of rows = %d", self.numberOfRows);
}
else
{
self.numberOfRows = self.numberOfRows + [newNumberOfItems intValue];
NSLog(#"New no rows = %d", self.numberOfRows);
}
NSLog(#"run = %d", self.run);
Begin updates if statement ...
/*if(self.secondRun){
NSLog(#"run = %d it it", self.run);
[self.tableView beginUpdates];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.numberOfRows-[newnumberOfItems intValue] inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath]withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
}
*/
[self.tableView reloadData];
}
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell" forIndexPath:indexPath];
cell.textLabel.text = self.nameOfItem;
return cell;
}
...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.numberOfRows;
}
If you want to add new items to a new section every time you call -addNew…, you should create an NSMutableArray of sections where each member is an array of objects representing row data (in this case seems like you'd want NSStrings that represent the item's name. The structure would look something like:
mySections = #[ #[#"section 0 row 0 name", #"section 0 row 1 name", …], #[#"section 1 row 0 name", #"section 1 row 1 name", …], …]
Then in numberOfRowsInSection: return mySection[indexPath.section].count.
Each label has the same value because you're setting every single label for every cell that you dequeue to self.nameOfItem. It's doing exactly what you told it to do. If your intent is to set a different text for every section/row, you have to fetch that text from somewhere. If you created a mySections array as above, you could:
cell.textLabel.text = mySections[indexPath.section][indexPath.row] ;
A note about -addNew:…: simply adding new items to your mySections array will not cause the tableview to update. As you know above, [self.tableView reloadData] will do this for you. However, it will reload the entire table instead of just updating the rows that you added. To do this more efficiently (and with a nice animation), you instead use [self.tableView beginUpdates/endUpdates]. In the case above, where you're adding entire sections and not just rows, you should use insertSections:withRowAnimation:.

Can't delete row in UITableView

Hi the following function doesn´t work for me and i don´t get why....
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source
NSString *selectedCategory = [self.daten objectAtIndex:indexPath.row];
[self.daten removeObjectAtIndex:indexPath.row]; //we assume, that mySourceArray is a NSMutableArray we use as our data source
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
// ...
}
}
I don´t have any Sections...I always get that exception:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (19) must be equal to the number of rows contained in that section before the update (19), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
* First throw call stack:
(0x342692a3 0x33a3b97f 0x3426915d 0x3922e2af 0x36dd5b83 0x5453d 0x36f6b5d9 0x36e8c0ad 0x36e8c05f 0x36e8c03d 0x36e8b8f3 0x36e8c0ad 0x36e8c05f 0x36e8c03d 0x36e8b8f3 0x36e8bde9 0x36db45f9 0x36da1809 0x36da1123 0x34f195a3 0x34f191d3 0x3423e173 0x3423e117 0x3423cf99 0x341afebd 0x341afd49 0x34f182eb 0x36df5301 0x24343 0x38e34b20)
libc++abi.dylib: terminate called throwing an exception
You need to update your number of rows in numberOfRowsInSection: method. As i can see, you need to return your [self.daten count] in this method.
As its told, the system checks this number before/after update/delete to keep data integrity.
You always have a section :)
Implement it like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.daten count];
}
Also, remember that you need to set both UITableViewDelegate and UITableViewDataSource to self.
OK, the problem is: NSMutableArray's removeObjectAtIndex: method does not resize it. So you have to handle it by yourself. Create new array with right capacity and move the rest of elements to it. You can google how to resize NSMutableArray.

Resources