Inserting Row at Index path issues - ios

I am creating an iOS app that is set up as a hierarchy of data. I have no issues on the first page adding and deleting objects or even transitioning to the next page. The problem occurs on the second page which is set up exactly like the first. When I press the add button to add an object the program crashes and sends back the error SIGABRT.
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES]; << crashes on this line
here is the function add tapped:
- (void)addTapped:(id)sender {
StudentDoc *newDoc = [[[StudentDoc alloc] initWithTitle:#"New Student" rating:0 thumbImage:nil fullImage:nil] autorelease];
[_students addObject:newDoc];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count-1 inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}
number of rows in section:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _students.count;
}
I have been under the impression that the count is what is causing the problem, but I have monitored the count and it stays consistent.
Overall I have no idea why it is crashing at this point because the page before it uses the exact same function to add objects on that page. Any ideas?

Normally if you'd messed up your array or row indexes you'd expect an exception to be logged in the console, not a SIGABRT. Have you enabled NSZombies and break-on-exceptions in Xcode? That may help to diagnose the issue.

You should put insert row at index path between begin updates and end updates block.
- (void)addTapped:(id)sender {
StudentDoc *newDoc = [[[StudentDoc alloc] initWithTitle:#"New Student" rating:0 thumbImage:nil fullImage:nil] autorelease];
[_students addObject:newDoc];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count-1 inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES];
[self.tableView endUpdates];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}

I've done almost the same, tho I split it into 2 lines:
NSInteger idx = [_students count] - 1;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
I wonder if that would make a difference.

You're adding an object to the data source, but replacing an existing row in the table, not adding one, resulting in one row in the indexPath but 2 items in the data source array.
For instance, if you have one item in _students, you'll have one index path, {0,0}. When you add a row, you're adding it at indexPath {_students.count - 1, 0}, which would be {1 - 1, 0} or {0, 0}. Your data source should match any indexPaths you insert or remove, and in your case you're always ending up with one more item in your data source than you add/remove.
If you always want to add an item, instead of:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count-1 inSection:0];
You want:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count inSection:0];

Related

Move index path by one in TableView (iOS)

I have a chat application, in which i want to increase the index path by one when new chat data come. But it is not happening through my code I am sharing code with screen shot please help.
NSUInteger messageCount = [self numberOfMessages];
if (self.conversation && messageCount > 0) {
NSLog(#"%ld",(long)indexPathValue.row);
NSIndexPath* ip = [NSIndexPath indexPathForRow:indexPathValue.row + 1 inSection:0];
NSLog(#"%ld",(long)ip.row);
[layerChatTableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
Below code allows you to go last indexpath with scroll position of bottom.
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:messageCoutnt-1 inSection:0] atScrollPosition:UITableViewScrollPositionButtom animated:NO];
Try and let me know
I am assuming that you have handled the datasource updating part and that you are updating the table view on main thread.
You can try to add new row at bottom like this:
NSInteger section = 0;
NSInteger newCount = [self tableView:self.tableView numberOfRowsInSection:section];
NSMutableArray *paths = #[].mutableCopy;
[paths addObject:[NSIndexPath indexPathForRow:newCount inSection:section]];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
You can also add more than 1 row with some modifications.
Hope this helps.

iOS - UITableView Delete All Rows Within A Section

I have a UITableView with expandable sections. When a user goes to another view, I need all the expanded sections to collapse, which I'll need to put in the viewWillDisappear method.
I've found solutions only on how to delete all rows from a table view at once, but is there a way to delete all the rows from a specific section?
EDIT:
I have figured out a solution, but I'm not sure if it's optimal or can lead to inefficiencies in the future. Whenever a cell is expanded, it gets added to an NSMutableIndexSet. So in my viewWillDisappear method, I iterate over the expanded sections like so:
-(void)viewWillDisappear:(BOOL)animated
{
if (expandedSections.count != 0) {
NSLog(#"COLLAPSING CALLED");
[self.tableView beginUpdates];
NSUInteger section = [expandedSections firstIndex];
do
{
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
rows = [self tableView:self.tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
for (int i=1; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
[self.tableView deleteRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
NSIndexPath *expandableCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:expandableCellIndexPath];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[self.colorHolder objectAtIndex:section] type:DTCustomColoredAccessoryTypeRight];
section = [expandedSections indexGreaterThanIndex:section];
} while (section != NSNotFound);
[self.tableView endUpdates];
}
}
Please let me know if this is a good solution or, if I'm suspecting correctly, if this will lead to slower transitions between views in the future when there are more rows in each expanded section. Any help or advice would be appreciated. Thanks.
If you want to animate changes, you will need to first update your data source (to return 0 for number of rows in the section) then remove section and add section at the same index path in one transaction between [tv beginUpdates] [tv endUpdates]
Otherwise just update the data source and reload the table on your way back to the VC (if you don't want any animations)
I did not read this in detail but surely the for loop should start at zero.
for (int i=0; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
otherwise you will only delete all but the first cells in the section.

how to access tableview cell

i have a menu that contain 6 cells 1st one contain UIViewController the second contain UITableView
when i click the first cell a new page appear,and it contain a button
when i click this button i want access to the second cell from the Menu, that contain a tableView
// use this code for to Refresh or delete or insert TableviewCell
// reloading cell
NSIndexPath *tmpIndexpath=[NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:tmpIndexpath, nil] withRowAnimation:UITableViewRowAnimationTop];
// inserting cell
NSIndexPath *tmpIndexpath=[NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:tmpIndexpath, nil] withRowAnimation:UITableViewRowAnimationTop];
// deleting cell
NSIndexPath *tmpIndexpath=[NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:tmpIndexpath, nil] withRowAnimation:UITableViewRowAnimationBottom];
As much i understand your question you want to move from a tableview to other view on click..So,you have to use code similar to this..
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
Detail *img1=[[Detail alloc]initWithNibName:#"Detail" bundle:Nil];
img1.labelString = [titleArray objectAtIndex:indexPath.row];
[self presentViewController:img1 animated:YES completion:nil];
}
Write following coed in your UIButton Tapped Method.
-(void) ButtonTapped:(UIButton *) sender
{
NSIndexPath *indexpathNew = [self.tblView indexPathForCell:(UITableViewCell *)[sender superview]];
NSLog(#"%#",indexpathNew.row);
}
indexpathNew is return indextPath of selected button of cell.
Try my code i might be helpful to you.

Tableview reload data not updating tableView

The else part of this works fine. But if itemFlag is true, I can't get the new information to display itself correctly after doing the alphabetic sort. Quitting the programme and restarting shows the new item to have been added successfully to the array, and everything is diplayed correctly.
So my question is, why is reloadData not working if itemFlag is true?
Here is the code:
- (void)changeFoodDetails:(NSString *)foodName withPoints:(NSString *)foodPoints{
if (newItemFlag) {
[_foodStuffsArray insertObject:[[FoodItem alloc] initWithName:foodName points:[foodPoints intValue]] atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[sharedManager sortFoodStuffArrayByName];
[self.tableView reloadData];
newItemFlag = false;
}else {
[_foodStuffsArray removeObjectAtIndex:currentFoodstuffArrayEntry];
[_foodStuffsArray insertObject:[[FoodItem alloc] initWithName:foodName points:[foodPoints intValue]] atIndex:currentFoodstuffArrayEntry];
[self.tableView reloadData];
}
}

Add cell/data to the top of UITableView

I'm trying to create a simple chat application for iOS. It currently looks like this:
I want to change the order that the messages is displayed, i.e. display the latest message over the older messages. My current implementation looks like this:
// Datasource for the tableView
messages = [[NSMutableArray alloc] init];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[...]
// messageTextView is a contentView subView.
messageTextView.text = [messages objectAtIndex:indexPath.row];
[...]
- (IBAction)sendMessage:(id)sender
{
[messages addObject:messageField.text];
messageField.text = #"";
[self.tableView reloadData];
/*
I have tried the implementation below, but I always got an exception.
[self.tableView beginUpdates];
NSIndexPath *path1 = [NSIndexPath indexPathForRow:1 inSection:0];
NSArray * indexArray = [NSArray arrayWithObjects:path1,nil];
[self.tableView insertRowsAtIndexPaths:indexArray
withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
*/
}
Any tips on how to do this would be great.
Thanks.
Simple you need to insert the new UITableViewCell at the 0 index. Also modify your Datasource otherwise your app will crash. Below I show how to modify your UITableView. Modifying your datasource is easy.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
What you are essentially doing here is inserting the new chat message cell at the 0th index position. You could use a nice animation effect to make it appear or fade in.
There are various animations that you can use here-
UITableViewRowAnimationBottom
UITableViewRowAnimationFade
UITableViewRowAnimationMiddle
UITableViewRowAnimationNone
UITableViewRowAnimationRight
UITableViewRowAnimationTop
You can try.
[messages insertObject:messageField.text atIndex:0];
instead of [messages addObject:messageField.text];.
Swift Solution
Define array like this
var arrMessage = [AnyObject]()
and Button Action
#IBAction func btnSendMessageTapped(sender: AnyObject) {
arrMessage.insert(txtTypeMessage.text!, atIndex: 0)
txtTypeMessage.text = ""
self.tblMessage.reloadData()
}

Resources