Application crashed when calling selectRowAtIndexPath - iphone

In my application I have an UITableView with dynamic number of rows. Once user click on a cell, the application navigates to another UIView and user can click the back button to go to the UITableView. When going back I wanted to highlight the selected cell and scroll the cell to the center. This is how I achieve it
-(void) tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (!isScrollerSet && self.selectedRowNo!=-1) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.selectedRowNo
inSection:0];
[self.tableViewP selectRowAtIndexPath:indexPath
animated:YES
scrollPosition:UITableViewScrollPositionMiddle];
isScrollerSet = YES;
}
}
When the user comes back this method will be call when the rows are displayed again. I set the correct row number in the didSelectRowAtIndexPath: method.
When the UITableView has less numbers of rows this works fine. Lets say UITableVIew have 100 rows and user clicked on 90th row. When he comes back application crashed when calling the didSelectRowAtIndexPath: method. Exception is as follows
*** Terminating app due to uncaught exception 'NSRangeException',
reason: '*** -[__NSArrayM objectAtIndex:]: index 3 beyond bounds
for empty array'
Then I move this code to viewDidAppear:. Now it woks with with any number of rows. I cant figure out why this happen. Can some one explain what was the reason?

Assuming that you do not have defective code it is possible that:
-(void) tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
is called before your Datasource is initialized. For example, if your UITableView is instantiated in the UIViewController's viewDidLoad function, and then you initialize your Datasource afterwards then upon reloading the UITableView you will have a nil value.
Whereas viewDidAppear occurs later in the runtime than viewDidLoad so at that point your Datasource is valid and you're able to reference that index in the NSArray. If this is the cause of your exception then you would be able to solve it by doing your Datasource initializing at the very beginning of viewDidLoad.
This is my best guess based on the information you provided. You may want to give more detail in your question.

tableView willDisplayCell
method is called before your data is loaded.so deferentially it will show an error because it is not getting any index position because of no data in tableview
So the solution is that you can set an integer or any other variable and check it inside cellforRowAtindexpath. when you return back..(Better to store value in UserDafault)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if(indexpath.row==<your value>)
{
// your code.
}
....
}

Related

How do you retain the current IndexPath.row in a Table View when going from one View Controller to another such as Instagram or Facebook in Swift?

I am trying to retain the current IndexPath.row of a cell in a Table View when passing from one View Controller to another such as Instagram or Facebook. Every time I move from one View Controller to another, I have to call reloadData() for the Table View to load it back. But when I do this, I lose the current position before going to a new View Controller.
I can get it to work on didSelect by passing the current IndexPath.row between Controllers, but if the user is just scrolling, it becomes buggy trying to do that.
Any suggestions would be greatly appreciated! Thanks so much!
By default, reloadData keeps the contentOffset. However, it could be updated if you do have inaccurate estimatedRowHeight values.
Calling reloadData on the tableView does not change the content offset. However, if you are using UITableViewAutomaticDimension which was introduced in iOS 13, you could have an issue.
While using UITableViewAutomaticDimension, one needs to write the delegate method tableView: estimatedHeightForRowAtIndexPath: and return UITableViewAutomaticDimension along with tableView: heightForRowAtIndexPath: which also returns the same.
For me, I had issues in iOS 13 while using this. It was because the method estimatedHeightForRowAtIndexPath: method was returning inaccurate values even though I was using UITableViewAutomaticDimension. It was problem with iOS 13 as there was no issue with iOS 13 devices.
I solved this problem by using a dictionary to store the value of the cell's height and returning it. This is what I did.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *key = #(indexPath.row);
NSNumber *height = #(cell.frame.size.height);
[self.cellHeightsDictionary setObject:height forKey:key];
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSNumber *key = #(indexPath.row);
NSNumber *height = [self.cellHeightsDictionary objectForKey:key];
if (height)
{
return height.doubleValue;
}
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
as u said u can save the position and in viewDidLoad of the new viewController scroll to that index:
tableView.scrollToRow(at: <IndexPath>, at: <UITableView.ScrollPosition>, animated: <Bool>)
set animated to false and scrollPosition to whatever fits u, example .top, and the indexPath u just pass between view controllers. try to alternate where to use this function in viewDidLoad or viewWillApear.

How to delete a row from table view IOS

I want to delete a row from table view without using the below data source method. How to do it?
- (void) tableView : (UITableView *)tableView
commitEditingStyle : (UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath : (NSIndexPath *)indexPath
How about [UITableView deleteRowsAtIndexPaths: withRowAnimation:]?
(I've linked Apple's documentation linked for you).
#Scar's idea is also good, but that will refresh the entire table and that might be a bit disruptive to the user if they're scrolled to the bottom of the table and the refresh takes them to the top.
Not quite that simple, you have to do this atomically with a UITableView
[_tableView beginUpdates]; // <-- pretty important
long selectedRow = _tableView.selectedRow;
[_tableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:selectedRow] withAnimation:NSTableViewAnimationSlideUp];
//then remove your object from the array
[((NSMutableArray*) _searchResults) removeObjectAtIndex:selectedRow];
[_tableView endUpdates];
This prevents delegate methods from being called while the array is being updated.
Remove the row from your model and call -deleteRowsAtIndexPaths:withRowAnimation:.

ios 5 UISearchDisplayController crash

I am implementing a UITableView with UISearchDisplayController in xcode 4.2.
UITableView & UISearchDisplayController are created in StoryBoard.
I set the Cell Identifier (SampleCell) for UITableView and access it like
cell = [tableView dequeueReusableCellWithIdentifier:#"SampleCell"];
UItableView is working fine.
But once i try to search, the app crash with below error.
*** Assertion failure in -[UISearchResultsTableView _createPreparedCellForGlobalRow:withIndexPath:], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableView.m:6072
2011-11-09 22:22:16.058 SampleApp[14362:fb03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
I guess I need to set the cell identifier for self.searchDisplayController.searchResultsTableView cell.
But I don't know how.
Thanks in advance for any help. =)
Use [self.tableView dequeue...], not [tableView dequeue...].
The cell you're trying to dequeue is linked to your primary view controller's tableView in the storyboard, NOT the searchDisplayController's newly created tableView (which has no cell identifiers linked to it). If you just message "tableView" then your dequeue message goes to the searchDisplayController's tableView since that's what was passed into the cellForRowAtIndexPath:... method.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"CellId"];
// do your thing
return cell;
}
Hard bug to track indeed, it seems that every time you do a search a new tableview is created. Meaning that your cell registering has to be taken out of ViewDidLoad since this will only work for the first search. Instead use the following delegate method to do cell registering and customization:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
[self.searchDisplayController.searchResultsTableView
registerNib:[UINib nibWithNibName:#"YOURCELLNIB" bundle:nil] forCellReuseIdentifier:#"YOURCELLID"];
self.searchDisplayController.searchResultsTableView.separatorColor = [UIColor clearColor];
}
(The answer that recommends using self.tableview is dependent on another table view. This is the cleanest solution and can be used even if the search controller is used by itself.)
You need to register the cells on the UISearchDisplayController's UITableView. The best way to do that is to register the cells when that table view is loaded.
UISearchDisplayDelegate has a method that notifies you when the table view is loaded - just like viewDidLoad but for the search table view.
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
[tableView registerNib:[UINib nibWithNibName:#"MyCellNib" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"MyCellIdentifier"];
}
You can in
- (void)searchDisplayController:(UISearchDisplayController *)searchDisplayController didLoadSearchResultsTableView:(UITableView *)searchResultsTableView
do
[searchResultsTableView registerNib:[UINib nibWithNibName:#"someNibName" bundle:nil] forCellReuseIdentifier:#"yourReuseId"];
Then you're able to use in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
the normal
[tableView dequeueReusableCellWithIdentifier:

UItableView accessoryButton error

Hello I have a problem
I implement this method
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath: NSIndexPath *)indexPath
{
NSLog(#"Row=%i",indexPath.row);
}
If I run the app and tab on the DisclosureButton of the second row the output is "0". If I tab on the second row (not the DisclosureButton) the output is "1" (as aspected). The bug is only one the second row, all other rows work fine.
How can I fix this problem?
thanks

Objective C, How to load more data when user tries to scroll up at the bottom row of the tableview

I have UITableView and I want to load more data when user tries to scroll up at the bottom row of the tableview just like iPhone email application...What is the best way for this?
Implement the Delegate for UIScrollView and detect at which point where you want to load more data.
Or You can put the update code in the "cellForRowAtIndexPath:" method, here detect the row, say 100 and append the data, and remove the data in row <100 , you will have to check for dataSource's count before updating.
Append new contents to the Data Source (Array) and do this:
[self.tableView reloadData];
I tried adding this in UITableViewDelegate method "willDisplayCell"
(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row == floatRows - 1) {
floatRows += 10;
[tableView reloadData];
}
}
It is keep loading another 10 for every scroll to bottom.
Not sure, it will work for you.