Select row in tableview programmatically when row is not visible - ios

I have to select one by one cell in a tableview and "execute" this row to show their detailviewcontroller. I use the following code. Everything is working as it should be, as long as the next row to be executed is visible in the screen. Is the next cell in the red zone the user has to manually scroll to this cell and than it get's executed.
Any help
- (void)showNextExercise:(NSNumber *)nextOne{
int nextRow = [(NSNumber *)nextOne intValue];
NSLog(#"Next Row: %i", nextRow);
//Auto Start next Exercise //
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:nextRow inSection:0];
if ([self.tableView.delegate respondsToSelector:#selector(tableView:willSelectRowAtIndexPath:)]) {
[self.tableView.delegate tableView:self.tableView willSelectRowAtIndexPath:indexPath];
}
//[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition: UITableViewScrollPositionNone];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
if ([self.tableView.delegate respondsToSelector:#selector(tableView:didSelectRowAtIndexPath:)]) {
[self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}
[self performSelector:#selector(performSelectorWithDelay) withObject:nil afterDelay:0.2];
//END Auto Start next Exercise //
}
-(void)performSelectorWithDelay{
[self performSegueWithIdentifier:#"showDetail" sender:nil];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
if (![executedExercises containsObject:[NSString stringWithFormat:#"%#", [[object valueForKey:#"timeStamp"] description]]]) {
[executedExercises addObject:[NSString stringWithFormat:#"%#",[[object valueForKey:#"timeStamp"] description]]];
}
[autoExecutedExercises addObject:[NSString stringWithFormat:#"%#",[[object valueForKey:#"timeStamp"] description]]];
//[autoExecutedExercises addObject:[NSNumber numberWithLong:indexPath.row]];
if (indexPath.row == 0) {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
long warmUpTime = [userDefaults integerForKey:#"WarmUpBackup"];
NSLog(#"warmupBackUp: %li", warmUpTime);
}
}
Red Zone Image

What did you do exactly in tableView:didSelectRowAtIndexPath? Due to the reuse cell mechanism, invisible cells may not exist if you try to get them in tableView:didSelectRowAtIndexPath.

Don't abuse the UI system. You don't need to tell the table view delegate that a cell is going to be and then has been tapped on, you can just present the view controllers you require directly (call the method that presents without bothering the delegate).
You have the data that goes into the table view and you should be using that directly. Funnelling everything through the UI code is a burden and an application of knowledge and cross coupling in the code where there should be none.
If you wanted to show the table rows as selected, set a flag for the selected item in the data model (band scroll / reload the table). Now when the table is refreshed you can mark the cell.

Related

TableViewCell Swipe left to right and change content in DataBase table(CoreData)

I am new in IOS. And sorry for my week english, That time facing a problem. My problem is that I am using a CoreData in my project. In my project TableViewCell scroll left to right. Swipe is proper but I want to That cell are swiped and change database value. Particular indexpath.row are swipe and same row content change in DataBase table.
TableViewCell swipe by SWTableViewCell This Tutorial
- (void)swipeableTableViewCell:(SWTableViewCell *)cell scrollingToState:(SWCellState)state{
if(state ==1){
NSLog(#"animation start");
}
else
NSLog(#"animation end");
}
I am so tried many days but do not update DataBase table in same row on TableViewCell swipe, How can i do this, please help, ThankYou
Update answer
- (void)swipeableTableViewCell:(SWTableViewCell *)cell scrollingToState:(SWCellState)state{
if(state ==1){
NSIndexPath *indexPaths = [self.table_view indexPathForCell:cell];
NSManagedObject *selectedDevices = [self.devices objectAtIndex:[self.table_view indexPathForCell:cell].row];
NSLog(#"device %#",selectedDevices);
[selectedDevices setValue:#"OnTime" forKeyPath:#"time"];
NSError *saveError = nil;
[self.managedObjectContext save:&saveError];
if (saveError)
{
}
else
{
}
}
Based on the discussion in the comments you need to do follow these simple steps to achieve what you want
Set the tag of the cell in cellForRowAtIndexPath: method i.e. cell.tag = indexPath.row so that you can get the record from devices array later
In the delegate method of cell access the relevant NSManagedObject and update the value of time
Save these changes in the persistent store
Reload the cell at indexPath you just updated
The code would be something like:
NSInteger index = cell.tag;
NSManagedObject *device = [self.devices objectAtIndex:index];
[device setValue:[NSDate date] forKey:#"tine"];
NSError *error;
if ([context save:&error]) {
[self.tableView reloadRowsAtIndexPaths:[NSIndexPath indexPathForRow:index inSection:0] withRowAnimation:UITableViewRowAnimationAutomatic];
}

selectRowAtIndexPath not called

I have a class that allows a user to add entries to a server-side table. Everything works correctly until I attempt to refresh the UITableView with the new data. I make a server call to get the new dataset, use it to refresh the NSArray that is the data source for the table, and then attempt to reload the table. Here is the method that is called when the data comes back from the server:
- (void) logEntriesRefreshed : (NSNotification *) notification {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"log_entries_refreshed"
object:nil];
NSLog(#"returned from log entries fetch");
_logEntriesArray = [LogEntriesDataFetcher getLogEntriesArray];
[_tableView reloadData];
_activityIndicator.hidden = YES;
[_activityIndicator stopAnimating];
NSLog(#"log entries array count: %lu", [_logEntriesArray count]);
[_tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
animated:NO
scrollPosition:UITableViewScrollPositionNone];
}
It's this last line that is the problem. I want to programmatically select the first row in the table (there has to be at least one, since I just added a row). But it appears that this line never executes. Note this method, which should go next:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"here");
UITableViewCell *previousCell = (UITableViewCell *)[_tableView cellForRowAtIndexPath:_previousIndexPath];
previousCell.backgroundColor = [UIColor clearColor];
previousCell.textLabel.textColor = [SharedVisualElements primaryFontColor];
UITableViewCell *cell = (UITableViewCell *)[_tableView cellForRowAtIndexPath:indexPath];
cell.contentView.backgroundColor = [SharedVisualElements secondaryFontColor];
cell.textLabel.textColor = [SharedVisualElements primaryFontColor];
_previousIndexPath = indexPath;
// get the file attributes for the cell just selected
_currentEntry = (LogEntry *)[_logEntriesArray objectAtIndex:[indexPath row]];
NSLog(#"array count: %lu", (unsigned long)[_logEntriesArray count]);
NSLog(#"current entry: %ld", (long)[indexPath row]);
_isExistingEntry = YES;
_arrayPositionOfEntryBeingEdited = [indexPath row];
[self initializeValues];
[self initializeObjects];
[self captureStartingValuesForStateMachine];
}
I have break points set on the selectRowAtIndexPath line and also on the first NSLog(#"here") line in didSelectRow.... I get to the selectRowAtIndexPath line but never to the didSelectRow method. My console output is consistent with that:
returned from log entries fetch
log entries array count: 7
and that is the end of it. Nothing from the didSelectRow... method. There are no errors thrown, either.
What am I missing. Seems pretty straightforward, but nothing I do seems to work.
As per Apple's documentation, calling selectRowAtIndexPath will NOT invoke the didSelectRowAtIndexPath. Take a look here.
Calling this method does not cause the delegate to receive a
tableView:willSelectRowAtIndexPath: or
tableView:didSelectRowAtIndexPath: message, nor does it send
UITableViewSelectionDidChangeNotification notifications to observers.
To specifically invoke the didSelectRowAtIndexPath delegate method, use the following code:
[[tableView delegate] tableView:tableView didSelectRowAtIndexPath:indexPath];
Hope this helps.

Add new UITableView row with custom text

Using this code
- (IBAction)testAdd:(id)sender
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.numberOfRows inSection:0];
[self.tableView beginUpdates];
self.numberOfRows++;
[self.tableView insertRowsAtIndexPaths:#[indexPath]withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
}
I'm able to add a new item to a tableView via an 'add' button on the app. This basically adds an item identical to the item already on the table that preceded it.
For example, I have a tableview with the first row displaying a string "TEST", hitting add adds another row that displays "TEST".
I would like to be able to pass in a custom value for the new row, so hitting add outputs a row with say "NEWTHING".
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell" forIndexPath:indexPath];
// Configure the cell...
cell.textLabel.text = self.val2;
return cell;
}
My data source is actually another view controller that takes user inputs and sends it to my tabelViewController, with the text for the item as "val2".
What I actually want to achieve is the ability to hit add, go back to the user input view controller, get the new data and send it back to my tableViewController to be displayed
What you're asking, is the kinda stuff that is to be done in -cellForRowAtIndexPath: (most of the times, it depends on the way you have designed your datasource) but if it doesn't matter to you, then you can do:
- (IBAction)testAdd:(id)sender
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.numberOfRows
inSection:0];
self.numberOfRows++;
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[cell.textLabel setText:#"NEWTHING"];
}
But note that when you scroll far up/down and return to this cell, it will most probably show "TEST" (that's where -cellForRowAtIndexPath: will show it's true purpose)
PS: Include your -cellForRowAtIndexPath: method implementation in the question if you want to proceed further
EDIT:
Your -cellForRowAtIndexPath is too static... in the sense that it simply sets self.val2 to cell.textLabel.
Lets say you start with 10 rows, -cellForRowAtIndexPath will be called 10 times and every time, it will set self.val2 onto the current cell's textLabel.
Now... when you add one row (on a button tap), the -cellForRowAtIndexPath will be called for the 11th cell and the same* text will be set to it.
*this technically happened but we quickly changed the cell's text
Basically, the tableView doesn't know how to differentiate between an existing cell and a new added cell because the datasource itself is not dynamic.
To direct the tableView on how to handle different cells, we need to create a more dynamic datasource.
There are different approaches use but I'd generally do it this way:
- (void)viewDidLoad
{
[super viewDidLoad];
self.val2 = #"TEST";
//declare "NSMutableArray *arrDatasource;" globally
//this will be the soul of the tableView
arrDatasource = [[NSMutableArray alloc] init];
int i_numberOfCells = 10;
//populate beginning cells with default text
for (int i = 0; i < i_numberOfCells; i++) {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:self.val2 forKey:#"displayText"];
[arrDatasource addObject:dictionary];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//return number of objects in arrDatasource
return arrDatasource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell" forIndexPath:indexPath];
//pick up value for key "displayText" and set it onto the cell's label
[cell.textLabel setText:arrDatasource[indexPath.row][#"displayText"]];
//this will be dynamic in nature because you can modify the contents
//of arrDatasource and simply tell tableView to update appropriately
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//make indexPath of new cell to be created
NSIndexPath *indexPathNEXT = [NSIndexPath indexPathForItem:arrDatasource.count inSection:0];
//add the appropriate contents to a dictionary
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:#"NEWTHING" forKey:#"displayText"];
//add the dictionary object to the main array which is the datasource
[arrDatasource addObject:dictionary];
//add it to tableView
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexPathNEXT]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
//this ends up calling -cellForRowAtIndexPath for the newly created cell
//-cellForRowAtIndexPath shows the text (you put in the dictionary in this method above)
}
PS: -cellForRowAtIndexPath: is called whenever cell updates or refreshes or needs to be displayed and so this method needs to be implemented properly

UITableViewCell loses highlighted selection

I am using [tableview reloadData]; to reload the data in my UItableView, however when I use this I loose my highlight on my UItableVewCell.
I would like to know the best way to reinstate this highlight.
I set a tempIndexPath when the user selects the cell they edit the information then I call reloadData, then inside cellForRowAtIndexPath I use this code to re-highlight the cell however its not working.
if ([tempIndexPath isEqual:indexPath]) {
cell.selected = YES;
}
This code keeps the highlighted selection, and is safe with resorting/inserts/repositioning since it keeps a reference to the underlying object from the model, instead of the index path. It also scrolls to the selection, which is helpful when the updated model causes the selection to be moved out of the current scroll position's frame.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Save the selected object at this row for maintaining the highlight later in reloadData
_selectedItem = [_items objectAtIndex:indexPath.row];
}
- (void) reloadData
{
[_itemsTable reloadData];
//Reselect and scroll to selection
int numItems = _items.count;
for (int i = 0; i < numItems; i++) {
NSDictionary *dict = [_numItems objectAtIndex:i];
if (dict == _selectedItem) {
//This is more reliable than calling the indexPathForSelectedRow on the UITableView,
// since the selection is cleared after calling reloadData
NSIndexPath *selectedIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
[_itemsTable scrollToRowAtIndexPath:selectedIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
[_itemsTable selectRowAtIndexPath:selectedIndexPath animated:FALSE scrollPosition:UITableViewScrollPositionNone];
break;
}
}
}
Save the selected row, reload your table view's data and select the row again.
NSIndexPath* selectedIndexPath = [tableView indexPathForSelectedRow];
[tableView reloadData];
[tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
You should know that this is dangerous, because if new items were added to the table view before the selected row, the selection will not be the correct cell. You should calculate how many rows were inserted before the row and adjust the selectedIndexPath accordingly.

'NSInternalInconsistencyException', reason: 'attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update'

Im pretty new at iOS programming, I'm trying to make this budget app. I want to add a instance class of my budget class to my tableview. But when I'm hitting the done button this error comes up. I've been searching the forum for an answer to my problem.
So fare I've found Aby how has the same problem as I (http://stackoverflow.com/questions/11706254/nsinternalinconsistencyexception-reason-attempt-to-insert-row-0-into-section?answertab=active#tab-top) but I can't really get a clear answer/solution to my problem in that post.
I'm quit sure I know why this error happens, but how do solve it I don't know :-(
Any who can help me solving this problem?
I would like to post some pic of my code but stackoverflow will not allow me due to spam securing.
AddBugdetViewController.m
(IBAction)done
{
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
Budget *budget = [[Budget alloc] init];
budget.name = self.textField.text;
budget.amount = [Budget convertStringToNSNumber:self.textField.text];
[self.delegate addBudgetViewController:self didFinishAddingItem:budget];
}
BudgetViewController.m
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.budget.items count];
}
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Budgets"];
Budget *item = [self.budget.items objectAtIndex:indexPath.row];
[self configureTextForCell:cell withChecklistItem:item];
return cell;
}
- (void)addBudgetViewController:(AddBudgetViewController *)controller didFinishAddingItem:(Budget *)NewBudget
{
NSLog(#"Adding budget: %#", NewBudget.name);
NSLog(#"Budget amount: %#", NewBudget.amount);
[self.tableView beginUpdates];
int newRowIndex = [self.budget.items count];
[self.budget.items addObject:NewBudget];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:newRowIndex inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
[self dismissViewControllerAnimated:YES completion:nil];
}
Please tell me if you need more information to track down the problem and solve it :-)
Cheers Anders
Your BudgetViewController appears to define a property named 'budget'. Whatever code is creating and displaying the BudgetViewController should set that property to whatever budget object should be displayed in the view controller.

Resources