exception while deleting cell - iphone

i am trying to delete a cell from my table view but it's displaying exception:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[RootViewController aBook]: unrecognized selector sent to instance 0x3d217a0'
here is my code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSLog(#"handover values to object");
Book *aBook = [appDelegate.books objectAtIndex:indexPath.row];
NSLog(#"removing");
[[self aBook] removeObjectAtIndex:[indexPath row]];
NSLog(#"deleting row");
// Animate deletion
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[[self tableView] deleteRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationFade];
}
control displays exception at 8th line after printing "removing" word. also giving warning that "root view controller not responding to aBook"
help!!

Why are you calling [self aBook]? It's local object! Try [aBook removeObjectAtIndex: ]

The runtime already gives you a very good explanation of what's wrong: You are sending a aBook message to an object of type RootViewController (the class in which you implemented the posted code).
So, [self aBook] is not valid.
Also, accept more answers.

perhaps you mean
[aBook removeObjectAtIndex:[indexPath row]];

Related

Cell autoreleased and "unrecognized selector sent to instance"

Probably my code crashes in the following method, since the getData() is called only once - at the end of this method.
Moreover the didSelectRowAtIndexPath code is the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath
{
[tableView deselectRowAtIndexPath:newIndexPath animated:YES];
// Set
[[GlobalObject obj] setData:[(CustomCell*)[tableView cellForRowAtIndexPath:newIndexPath] getData]];
}
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CustomCell getData]: unrecognized selector sent to instance.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section == 0)
{
...
return cell;
}
else
{
// Create a button table view cell
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
if (cell == nil)
{
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CustomCell"] autorelease];
}
[cell setButton:[ ...];
return cell;
}
}
As shown above the cell is autoreleased and probably this is the reason the app crashed. Cell went to the autorelease pool and then getData sent to an unrecognized selector. How can I resolve the issue?
CustomCell does noth have a method called getData.
Avoid inlining, write the statements one after another. This helps in debugging. You easily can then set a breakpoint.

Is there a trick to Insert rows into a TableView w/ Static Cells configured via Storyboard?

I've got a TableView that I've created in a Storyboard via Static Cells.
The idea is that a section has a single row with a Label and a Switch. When the user taps the Switch "on", the section sprouts some new rows below. Somewhat similar to Wi-Fi settings in the Settings app (which adds new sections, but I'm adding new rows).
I'm creating this TableView via Storyboard like so:
And now, the action taken when the switch value changes:
- (IBAction)hitSwitch:(id)sender {
NSArray *indexPathsArray = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1 inSection:0], [NSIndexPath indexPathForRow:2 inSection:0], nil];
UISwitch *theSwitch = sender;
[self.tableView beginUpdates];
if (theSwitch.on) {
[self.tableView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationAutomatic];
} else {
[self.tableView deleteRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self.tableView endUpdates];
}
I'd expect the normal table view data source methods to be called to display the cells for these new rows, so I've added the following code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (self.addRowsSwitch.on) {
return 3;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (!self.addRowsSwitch.on) {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
} else {
UITableViewCell *newCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
return newCell;
}
}
But according to my handy debugger, tableView:numberOfRowsInSection: is called, returns a value, and then the app crashes before tableView:cellForRowAtIndexPath is called.
2012-08-02 13:16:08.564 TableViewInsertTest[3186:f803] * Terminating
app due to uncaught exception 'NSRangeException', reason: '*
-[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
*** First throw call stack: (0x14b2022 0xeb2cd6 0x149e644 0x43bea5 0x2481a8 0x1f3688 0x1f4c2a 0x9743e 0xa50b7 0xa50e5 0x2604 0x14b3e99
0x1814e 0x180e6 0xbeade 0xbefa7 0x212c16 0x93b85d 0x1486936 0x14863d7
0x13e9790 0x13e8d84 0x13e8c9b 0x139b7d8 0x139b88a 0x15626 0x1ebd
0x1e25)
Is there something else I need to do to make this work, or is the type of behaivor that I'm trying to implement not supported?

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

Delete row from tableView

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.

App Crashes due to UITableViewScrollPositionMiddle when testing on phone but not emulator

I have a uitableview with an array of dictionary values producing a fairly big list.
That the user can select from.. once the user selects a cell I pop the view from the navigational stack and pass all the values back to the main view.. I then allow the user to go back to this view if they have made a mistake and would like to change their input.
when they click back to that view I have a method that automatically scrolls to the old selected view using UITableViewScrollPositionMiddle.
However I think its causing some errors when being used on the phone, as the emulator works fine.
here is where I think the error is happening
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//Center previously selected cell to center of the screen
[self.tableView scrollToRowAtIndexPath:oldCheckedData atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; //<--- this method
}
and this is the error I get in the log when building it to my phone. The process in order to get this error is for the user to click on the cell in the parent view that loads the subview, the user selects a cell in the subview and is taken back to the parent view.. then when the user goes back to the same subview this shows up in the log.
2011-10-19 15:00:05.790 icode[1564:707] -[__NSArrayM section]: unrecognized selector sent to instance 0x181cd0
2011-10-19 15:00:05.797 icode[1564:707] CoreAnimation: ignoring exception: -[__NSArrayM section]: unrecognized selector sent to instance 0x181cd0
(there is no scroll effect)
then the user selects a different cell and this app crashes and this shows up in the log
2011-10-19 15:01:08.272 icode[1564:707] -[__NSArrayM row]: unrecognized selector sent to instance 0x181cd0
2011-10-19 15:01:08.275 icode[1564:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM row]: unrecognized selector sent to instance 0x181cd0'
*** First throw call stack:
(0x35e9e8b3 0x366e61e5 0x35ea1acb 0x35ea0939 0x35dfb680 0x334a76cf 0x3353c713 0x30e1d 0x3352cd69 0x335a60ab 0x35cc32ab 0x35e72a57 0x35e726bd 0x35e71293 0x35df44e5 0x35df43ad 0x30fa4fed 0x334a7dc7 0x24f7 0x24a0)
terminate called throwing an exception(gdb)
any help would be greatly appreciated.
Tableview data sources
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [arraysByLetter count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *currentLetter = [sectionLetters objectAtIndex:section];
return [[arraysByLetter objectForKey:currentLetter] count];
}
/*
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
//override state-based properties set earlier by the table view, such as selection and background colorset up shit here
}
*/
- (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];
}
//Customize cell here
cell.selectionStyle = UITableViewCellSelectionStyleNone; // no blue selection
//Replaces previously selected cells accessory view (tick)
if (indexPath == oldCheckedData)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
//Display cells with data
NSArray *keys = [self.arraysByLetter objectForKey:[self.sectionLetters objectAtIndex:indexPath.section]];
NSString *key = [keys objectAtIndex:indexPath.row];
cell.textLabel.text = key;
return cell;
}
//Section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [sectionLetters objectAtIndex:section];
}
//Section header titles
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return sectionLetters;
}
It looks like the index path you have a reference to at oldCheckedData may have been deallocated when the view controller was popped from the stack. Make sure you retain it before the view controller goes away.