Delete row from tableView - iphone

I am a bit lost on what should be a simple action of deleting a row from a tableview. I have an sqlite database with a table called SUBJECT and I want to delete a record for this table, delete the member from the array and delete the entry in the tableview. I don't know what sequence is best and I keep getting errors.
Here is the code:
- (void)tableView:(UITableView *)tv commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if(editingStyle == UITableViewCellEditingStyleDelete) {
QuotesAppDelegate *appDelegate = (QuotesAppDelegate *)[[UIApplication sharedApplication] delegate];
//Get the object to delete from the array.
Subject *sub = [self.subjects objectAtIndex:indexPath.row];
// check if there are any quoteMaps for this subject and if so do not do it
NSArray *qm = [appDelegate getQuoteMapsFromSubId:sub.subject_id];
if (qm.count==0){
//Delete the object from the table.
[self.subjects removeObjectAtIndex:indexPath.row];
[tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[sub deleteSubject];
} else {
//DON'T DO IT BUT GIVE A WARNING INSTEAD
}
}
}
I get the following error on the self.subjects removeObject.... line:
-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x6b2a8f0
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x6b2a8f0'
The error message says my self.subjects is an NSArray yet my header assigns it as NSMutableArray:
#interface SubjectViewController : UITableViewController <UIAlertViewDelegate> {
NSMutableArray *subjects;
}
#property (nonatomic, retain) NSMutableArray *subjects;
Why is it changing to NSArray???
I checked and found that the Parent ViewController is assigning the following:
NSPredicate *catFilter = [NSPredicate predicateWithFormat:#"category_title == %#", cat.category_title];
NSArray *subs = [appDelegate.subjects filteredArrayUsingPredicate:catFilter];
subViewController.subjects = (NSMutableArray *) subs;
Looks like the problem is there.
I get the following error if I comment out the self.subjects removeObject and try to run the next line of "tv deleteRowsAtIndexPaths...":
*** 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).'
So far this was narrowed down to being a problem in the prior controller view where I am using an NSArray out of a NSPredicate because I couldn't get NSPredicate to work with NSMutableArray. So now that is the issue trying to be resolved.
Or converting/assigning an NSArray as an NSMutableArray...

NSArrays are inmmutable, that means you can't add or remove elements, hence your object doesn't have a removeObjectAtIndex: method.
Check your property to see if its an NSArray instead of an NSMutableArray.
Check that the object in that pointer is in fact an NSMutableArray.
To assign an NSArray to your variable first create an NSMutableArray from it using the arrayWithArray: method.

first your subjects array is immutable. use NSMutableArray class for subject array.
also try to use beginUpdates - endUpdates block...
[tv beginUpdates];
[tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tv endUpdates];

The error is being generated because your datasource, always has to be consistent with the rows added/deleted, which means if the previous call to the method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Returned x, and you deleted n rows, then the next call to the method after the delete animation MUST return (x-n)
Additionally if you are using an NSArray as your datasource and you will be adding/deleting rows then it MUST be immutable, as you have to keep your Array consistent with the adding/deletion. Therefore you need to use NSMutableArray.

Related

ios 5: Invalid update: invalid number of rows in section

I only have this problems with iOS 5, no problems with iOS 6
This is my log
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 3. The number of rows contained in an existing section after the update (3) 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, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
And my code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[dictionary allKeys] count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *keyArray = [dictionary allKeys];
return [[dictionary objectForKey:[keyArray objectAtIndex:section]] count];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
= if (editingStyle == UITableViewCellEditingStyleDelete)
{
//First get all the keys of dictionary into one array
NSArray *sectionsArray = [dictionary allKeys];
//Get all the data of tapped section into one array by using indexpath.section
NSMutableArray *objectsAtSection = [dictionary objectForKey:[sectionsArray objectAtIndex:indexPath.section]];
//remove the particular object by using indexPath.row from the array
[objectsAtSection removeObjectAtIndex:indexPath.row];
// Update dictionary
[table beginUpdates];
// Either delete some rows within a section (leaving at least one) or the entire section.
if ([objectsAtSection count] > 0)
{
[dictionary setObject:objectsAtSection forKey:[sectionsArray objectAtIndex:indexPath.section]];
// Section is not yet empty, so delete only the current row.
// Delete row using the cool literal version of [NSArray arrayWithObject:indexPath]
[table deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}else{
[dictionary removeObjectForKey:[sectionsArray objectAtIndex:indexPath.section]];
// Section is now completely empty, so delete the entire section.
[table deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
withRowAnimation:UITableViewRowAnimationFade];
}
[table endUpdates];
}
}
in iOS 5, after delete some row, and some section, i have this problems.
Could you please help me?
Need to add
[self.tableView reloadData];
and
self.editing = YES;
This is needed because the table view doesn't initially have information about its data source and delegate; if you create a table view, it always needs to be sent a reloadData message as part of its initialization.
Hope it will Help you
Ok, it seems I found an answer. See this SO question and answer, explaining why using allKeys method is bad.
As long as you don't add or remove any elements from the dictionary, they will remain in the same order, but as soon as you add or remove an element, the new order will be completely different.

Stop Tableview from crashing when array is empty?

At first my table view is empty, and then you can add your own cells to it. When you delete those cells, everything works fine. However, if you delete the last cell, then my NSMutableArray has no objects in it, and I get this error in my console (also, I'm using Core Data to save the cells):
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[_PFBatchFaultingArray objectAtIndex:]: index (123150308) beyond bounds (1)'
I also tried putting in this line of code, but I still get the same results:
//arr is my mutable array
if ([arr count] == 0) {
NSLog(#"No Cells");
}
This is how I delete an object from the table view:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[arr removeObjectAtIndex:0];
[context deleteObject:[arr objectAtIndex:0]];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
How would I solve this problem?
Ok.
There are two problems I have found in you code.
1- Why you are removing every time object at Index 0 ?
2- After removing an object from array[arr removeObjectAtIndex:0]; than from the same array of index you are passing an object to core Data to delete it
[context deleteObject:[arr objectAtIndex:0]];
This might be the problem.
This will surely help you.
Use this:
[context deleteObject:[arr objectAtIndex:indexPath.row]];
[arr removeObjectAtIndex:indexPath.row];
Thanks :)
If you look at the error message, the reason your code is failing is because some of your code is looking for a nonexistent index of 123150308. Without seeing your full code, it is impossible what exactly is wrong, but there is a simple fix.
A good way to solve the issue of an exception in code where the exception is "expected behavior" is to use #try blocks. This is your tableView method with #try blocks in place:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
#try {
[arr removeObjectAtIndex:0];
[context deleteObject:[arr objectAtIndex:0]];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
#catch (NSRangeException *exception) {
// Something was out of range; put your code to handle this case here
}
}
}
However, without the context of the rest of your app, it is impossible to tell if this is the error. If you try this and it doesn't work, then the error is deeper in your application

TableView app terminated due to 'NSInternalInconsistencyException'

I'm trying to get the hang of UITableViews and everything that goes with it. At the moment I have the following code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell.textLabel setText:[NSString stringWithFormat:#"I am cell %d", indexPath.row]];
return cell;
}
- (IBAction)killItem {
NSIndexPath *indexToDelete = [NSIndexPath indexPathForRow:2 inSection:0];
[tbl deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexToDelete] withRowAnimation:UITableViewRowAnimationRight];
}
And I get the following error when initiating the "killItem" function:
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 (10) must be equal to the number of rows contained in that section before the update (10), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).'
The way I understand it tableViews basically have a delegate and a data source where the data source, among other things, determines how many rows should be in the tableView. Through some searches here at stackoverflow I've found that this error is caused when the "data source doesn't match reality", when it's searching for rows that don't exist, that I have deleted.
I might have gotten this wrong but that's what I think is doing it. So my question is, how do I get these to match so that I can avoid this error?
For reference, I've looked in to the following posts without understanding what I need to do:
Error : Number of Rows In Section in UITableView in iPhone SDK
Slide UITableViewCell
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSMutableArray objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
Adding [tbl reloadData], [tbl beginUpdate] ... [tbl endUpdate] in the killItem function, doesen't seem to help my problem eighter.
Thank you in advance,
Tobias Tovedal
Tobias, what you need to do when deleting rows is
// tell the table view you're going to make an update
[tableView beginUpdates];
// update the data object that is supplying data for this table
// ( the object used by tableView:numberOfRowsInSection: )
[dataArray removeObjectAtIndex:indexPath.row];
// tell the table view to delete the row
[tableView deleteRowsAtIndexPaths:indexPath
withRowAnimation:UITableViewRowAnimationRight];
// tell the table view that you're done
[tableView endUpdates];
When you call endUpdate the number returned from tableView:numberOfRowsInSection: must be the same as the number at beginUpdate minus the number of rows deleted.
It's pretty easy, the problem lies here:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
The delegate pattern used by apple, means that you're the one responsible on managing the content of the UITableView through its delegates, meaning that, if you delete a row, you're also responsible of deleting the data from the data model.
So, after deleting a row, it would make sense that the number of rows in section would decrease to "9", yet, your function is always returning 10, and thus throwing the exception.
Typically, when using an table, and the contents will change, an NSMutableArray is pretty common, you do something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayWithStuff count];
}
And then, deleting an object (removeObjectAtIndex:) from the array would automatically update the number of rows.
(Edit: Replied at about the same time as Mike Hay, try following his advice too! I skipped the begin/end Update, because it seems you already read about it)

Error : Number of Rows In Section in UITableView in iPhone SDK

I am getting this error while I am trying to load the data into my table view.
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 (73) must be equal to the number of rows contained in that section before the update (71), plus or minus the number of rows inserted or deleted from that section (3 inserted, 0 deleted).
What could be wrong?
Thanks
EDIT :
I am initializing the array on ViewWillAppear and adding new objects to the same array on Tableview's didSelectRowAtIndexPath method
Here is the code On viewWillAppear :
cellTextArray = [[NSMutableArray alloc] init];
[cellTextArray addObjectsFromArray:newPosts];
Here is the code which modifies the array on didSelectRowAtIndexPath :
[cellTextArray addObjectsFromArray:newPosts];
NSMutableArray *insertIndexPaths = [NSMutableArray array];
for (NSUInteger item = count; item < count + newCount; item++) {
[insertIndexPaths addObject:[NSIndexPath indexPathForRow:item
inSection:0]];
}
[self.table beginUpdates];
[self.table insertRowsAtIndexPaths:insertIndexPaths
withRowAnimation:UITableViewRowAnimationFade];
[self.table endUpdates];
[self.table scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionNone
animated:YES];
NSIndexPath *selected = [self.table indexPathForSelectedRow];
if (selected) {
[self.table deselectRowAtIndexPath:selected animated:YES];
}
Here newPosts is an array which has the values that are added to cellTextArray on
didSelectRowAtIndexPath method and viewWillAppear method.
If you have updated the array of data after initialization then you can call this method [yourTable reloadData].
And, it be better if you post the codes here. Then may be some one can help you quickly.
I think, the problem is with the statement in the didSelectRowAtIndexPath method.
You have added the following statement
[self.table insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationFade];
This statement adds the new rows to the table. but the number of rows in the datasource array for that section is different with the number of rows in that section of that table.
So the App is terminated.
Please try by removing the above statement and add required data to the dataSource Array at required indexes and reload the table
Regards,
Satya

How can I make deleteRowsAtIndexPaths: work with GenericTableViewController?

I'm using Matt Gallagher's GenericTableViewController idea for controlling my UITableViews. My datasource is a NSFetchedResultsController.
http://cocoawithlove.com/2008/12/heterogeneous-cells-in.html
Everything is working fine, until I try to delete a cell.
I have the following code in my View Controller:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the managed object.
NSManagedObjectContext *context = [wineryController managedObjectContext];
[context deleteObject:[wineryController objectAtIndexPath:indexPath]];
NSError *error;
if (![context save:&error]) {
// Handle the error.
}
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
The final line crashes with the rather verbose explanation in the console:
*** 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 (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).'
OK, I understand what it is saying... a row is not getting deleted (I would assume) because I'm not forwarding some message to the right place (since I have moved some code from its 'normal' location)... anyone have any idea which one? I am totally stumped on this one.
Well, bah. I just found this answer, which is not the same, but got me headed in the right direction. I'll leave this here for anyone in the future having similar troubles.
The key is to wrap the deleteRowsAtIndexPaths with begin and end tags, and force the model to update within the same block, resulting in:
[tableView beginUpdates];
[self constructTableGroups];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
This caused the issue to go away, and the animations to work just perfectly.