I feel like this is an issue that requires special attention... my Google-fu is pretty good but I haven't been able to get anything useful.
This is the simplest thing, and yet I can't seem to figure out what the problem is with it.
I have a UITableView. It's a subview that my VC calls _form. I'm using it for styling purposes, not really to display data. It has 2 cells.
On a certain event, I'm trying to select a different cell, using selectRowAtIndexPath:animated:scrollPosition.
When I do this, it SIGABRTS.
A simple example:
- (IBAction)submitClicked:(id)sender
{
[_submit setTitle:#"Wha!?" forState:UIControlStateNormal];
NSIndexPath *row = [NSIndexPath indexPathWithIndex:0];
NSLog(#"%d", [[_form indexPathForSelectedRow] row]);
[_form selectRowAtIndexPath:row animated:YES scrollPosition:YES];
}
The button's title is changed, AND the table prints that the selected row is 0 or 1, but on trying to select the desired cell, it breaks:
2012-03-09 21:57:39.905 <omitted>[16329:207] 0
2012-03-09 21:57:39.908 <omitted>[16329:207] *** Assertion failure in -[NSIndexPath row], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableViewSupport.m:2598
(gdb)
My assumption is that this implies something is wrong with how my table is configured, but I'm not sure what. Selecting the cells in the table normally (clicking it) is working, as indicated by the expected response in my tableView:didSelectRowAtIndexPath. Everything else works fine with how I have this set up, except this.
(Also, I other people replying with extra debug info, not just "(gdb)". How can I get this?)
Thanks!
An indexpath for a tableview cell needs to have both a row and a section. Try creating your index path using the factory method (defined in NSIndexPath UIKit Additions) like this instead:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[_form selectRowAtIndexPath:indexPath animated:YES scrollPosition:YES];
Related
I have a method which is designed to clear all UITableViewCellAccessories and I get the following error when it is called
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.'
Here is the method
-(void)clearTableViewAccessories{
NSIndexPath *indexPath = [NSIndexPath new];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark){
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
The way you are initialising the indexPath object, creates an index path of length 0 and no path, which is formed by a section and a row.
You should create the indexPath with the designated initialiser
indexPathForRow:inSection:
Anyway I don't think your implementation is the best way to solve your problem. With your current setup you need to create an indexPath for every cell you want to create iterating through all of them, and you will get nil for any non-visible cell.
The best thing would be to start looking at UITableView dataSource methods, first of all tableView:cellForRowAtIndexPath: and inside here make the decision whether to clean the cell or not.
In your cellForRowAtIndexPath check if the cell should have no accessory. For example, you could modify your datasource or just use an ivar BOOL noAccessory. Set the accessory accordingly. Then simply call
[self.tableView reloadData];
Check your number or rows and number of sections , I had a similar issue which I solved by correctly populating number of rows in each section( if you have rows in section ). If you update the question with your data source eg array for section, and Rows , will be easier to answer
I have a tableView in my view and all works fine, however each custom cell (ToDoListCell) has a text field which I allow users to edit, updating their data. All good and well, my problem occurs whenever trying to scroll to a cell which is going to be hidden by the keyboard.
Note: I adjust the size of the table using the NSNotificationCenter observer methods as the Apple documentation recommends and I know this is not the problem.
- (void)scrollToSelectedCell {
NSIndexPath *currentIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
while (currentIndexPath.row < self.todos.count) {
ToDoListCell *cell = (ToDoListCell *)[self.table cellForRowAtIndexPath:currentIndexPath];
if (cell.titleField.isEditing == YES) {
[self.table scrollToRowAtIndexPath:currentIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
break;
}
currentIndexPath = [NSIndexPath indexPathForItem:currentIndexPath.row + 1 inSection:0];
}
}
Any idea why it does not scroll to any cell which is not currently on screen?
Thanks,
Ben
Just a guess, but probably because
ToDoListCell *cell = (ToDoListCell *)[self.table cellForRowAtIndexPath:currentIndexPath];
is returning nil causing cell.titleField.isEditing == YES to always fail. So the scroll command is never called. Table views only hold onto visible cells, so if you've resized your table view such that the cell being edited is no longer visible, you're going probably going to get nil back. You need to determine the index path of the cell being edited before resizing the table.
If you are firing the code in response to a notification listener, are you firing the notification from the UI thread?
UI animations will not perform unless executed on the main thread.
dispatch_async(dispatch_get_main_thread(), ^{
// send notification
});
I have a view with a map and and list displayed at the same time. I would like the map to move when the user scrolls the list.
I was hoping for something like
(UITableView*)tableView didScrollTableViewCellToTop:(UITableViewCell *)cell
I haven't found something that will support this yet.
Thanks in advance
You can get all the visibleCells by running...
NSArray *cells = [self.tableView visibleCells];
This returns an array of UITableViewCells.
You can then find the one with the lowest indexPath.row value to find the top one.
Remember that the UITableView is simply a scroll-view. So you can get the offset of the scroll view and use the position to get the cell at that location:
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: point];
To continuously monitor and change, implement a scroll-view-delegate and implement the scrollViewDidScroll method.
I have a tableview with custom cells with dynamic cell heights depending on the cell content.
My problem is the following, when I ask, programmatically, in the viewDidLoad, to scroll to a given position it works, except for the last row. Sometime the row appears but not fully, and sometimes it even does not appear. In both cases I have to scroll manually to see the row.
Here is the code :
[self.tableView reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:aRow inSection:aSection];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES ];
Is this a bug of iOS ? any workaround ?
As so far i came to know that,
All the operations used to before the view is shown on the screen are initialized in the viewDidLoad all the UI objects, data objects can be allocated and initialized in this method.
All the operations data modifications, UI modifications made to view need to be done in viewDidAppear. Or even some operations can be done in viewWillAppear.
So for your issue, the UITableView scrolling must be done after the table is loaded on & shown on screen i.e., in viewDidAppear.
Also note that viewDidAppear & viewWillAppear will be called each time view is shown to user, so if you want to scroll the table only for the first instance you can have a flag in your header indicating the instance.
[self.tableView reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
NSIndexPath *rowIndexPath = [NSIndexPath indexPathForRow:3 inSection:0];
[self.tableView scrollToRowAtIndexPath:rowIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
});
I don't know exactly why, but I guess this approach works because when we add(???) rows and call [tableView reloadData] tableView has no time to update some internal counters (like row counter) and calling [tableView scrollToRowAtIndexPath ...] has no effect since there is no such row at that time (again, probably correct in case you add rows or set tableView's data for the first time). Calling
dispatch_async(dispatch_get_main_queue(), ^{
...
});
after [tableView reloadData] gives tableView enough time to update row counter and perform scroll to existing row.
Vishy's approach works just because it gives enough time but applicable only if you need to scroll exactly one time when screen is loaded. Moreover it requires ugly flag to check every time viewDid/WillAppear.
I have problem with a long form in iOS. The form itself is done with a static table view. For the form I needed a toolbar with prev/next and done. In this project I added BSKeyboardControls, and I've allready done it myself in another project.
The toolbar works fine except when the next or previous textField/textView is out of sight. Then the focus on the former textField won't change and I'm still typing in this text field. When I now scroll manually and the targeted next textfield appears it magically becomes the first responder. This is of course not the expected behabier.
So I figured out I would have to scroll the table view to the respective fields before trying to set them as first responder. But I connot get this done.
I've tried to this with indexPathes
NSIndexPath *path = [self.tableView indexPathForCell:(UITableViewCell *)textField.superview.superview];
[self.tableView scrollToRowAtIndexPat:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
Although the super-superview is a valid (and the right) table cell, the path returned is nil. I also tried some variations
CGPoint point = [self.tableView convertPoint:textField.frame.origin toView:self.tableView];
NSIndexPath *path = [self.tableView indexPathForRowAtPoint:point];
and other variations with rects and indexPathsForRowsInRect.
The only way is to manually keep track of the textFields cell indexPaths, but that is no suitable solution in this case.
Anybody has an idea of how to achieve scrolling to an out of sight textField in a tableView?
Edit:
As Justin Paulson requested the code of keyboardControlsPreviousNextPressed:
- (void)keyboardControlsPreviousNextPressed:(BSKeyboardControls *)controls withDirection:(KeyboardControlsDirection)direction andActiveTextField:(id)textField
{
NSIndexPath *path = [self.tableView indexPathForCell:(UITableViewCell *)((UIView *)textField).superview.superview];
NSLog(#"path %# for cell %#", path, ((UIView *)textField).superview.superview);
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];
[textField becomeFirstResponder];
}
As I said according to the output of the log the path is nil, whereas the super-superview is the rught table view cell
Thanks for trying to help me, i've a solution myself. In my keyboardControlsPreviousNextPressed i have now
[self.tableView scrollRectToVisible:((UIView *)textField).superview.superview.frame animated:YES];
[textField becomeFirstResponder];
This solution seems to work quite well. The only problem i've encountered is that sometimes the newly focused textField is hidden by the keyboard, so the tableViewController doesn't adjusts itself automatically. You could additionally scroll the row to the top to circumvent this in most cases.
NSIndexPath *path = [self.tableView indexPathForCell:(UITableViewCell *)textField.superview.superview];
[self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionTop animated:YES];