cannot select UITableViewCell programmatically - ios

I am attempting to select, in the view did appear method, a table cell programatically.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:1];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
my delegate,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
does not get called.
The delegate gets called if i select the cells in the simulator with a mouse, however, just not programmatically.
Why can this be?

Because that's how the framework works. Try reading the docs. That's what they are for!
selectRowAtIndexPath:animated:scrollPosition:
Selects a row in the receiver identified by index path, optionally scrolling the row to a location in the receiver... Calling this method does not cause the delegate to receive a tableView:willSelectRowAtIndexPath: or tableView:didSelectRowAtIndexPath: message.
That's pretty easy to understand. The delegate method didSelectRowAtIndexPath: is not called if you select the row in code (programmatically). It is called only if the user selects the row.
And this makes perfect sense, because:
If you are selecting the row in code, you might not want the delegate method triggered.
If you do want the delegate method triggered, since you are in your own code, you can just call it.
You don't need the delegate method in order to learn that the row was selected, because you selected it in code - you cannot not know!

Related

Disable UITableViewCell selection by touch but enable by method call

What is the best way of preventing the user from selecting a cell inside a UITableView, but allowing my program to call selectRowAtIndexPath: on the table view?
I also want the controls in the UITableViewCell to remain interactive (i.e. allow touchesBegan: to be called on the UITableViewCell).
If I do [tableView setAllowsSelection:NO], calling selectRowAtIndexPath: does not do anything.
I realized that when you call selectRowAtIndexPath: programmatically, then the delegate method willSelectRowAtIndexPath: will not be called. However, if a user taps a cell, then this will be called. This method can return nil to prevent selection.
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
return nil;
}
This will ensure that only programmatic calls to selectRowAtIndexPath: will select a row and any taps to select a row will not.
Uncheck the box : User Interaction Enabled in TableView as well as TableViewCell

Is it possible to create UITableViewCells inside a for/in loop?

I'm calling a function in which i retrieve a NSDictionary with data that needs to be displayed in tableviewCells. Is it possible to call the method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
in another method?
It is not possible to call that one specific method inside another method. However, you can call [self.tableView reloadData] inside any methods. This call all the UITableView delegate methods which includes - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
You can explicitly call any methods of UITableViewDataSource and UITableViewDelegate, but should only be done in cases of dire need. In a project of mine, I get specific (subclassed) cells which draw elements not in the drawRect: method, but in a drawCell method I have defined, for performance gains (preventing offscreen rendering, etc).
Unless your cells have special drawing needs, (resizing subviews, etc) you should let the cellForRowAtIndexPath: method do this work for you.
Still, if you want to explicitly get cells, you may do with:
[yourTableView cellForRowAtIndexPath:indexPath];
This will return you your cell. Mind you, it will execute all relevant code inside the cellForRowAtIndexPath: including dequeueing, creation, and any other calls you have made in it.
indexPath passed here is an object of type NSIndexPath, and you may create one like this:
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:ROW_NUM inSection:SECTION_NUM];
Where, ROW_NUM is the is the row number inside the section, which is SECTION_NUM. For the first cell in the third section, the indexPath is:
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:2];//Since indices start at 0

Capture cell being pressed without didSelectRowAtIndexPath

I have the following UITableViewCell (well, subclassed).
With didSelectRowAtIndexPath it is possible to capture that a cell has been selected in UITableViewController. My problem occurs due to the fact that directly pressing Choose User bypasses the selection of the cell.
How could I allow my UITableViewController to be aware that UITableViewCell foo has been pressed even if the user immediately hits Choose User?
N.B. I don't need the Selection capability per se, this was just by method of knowing that a user had tapped within a cell area.
You could just call the method directly. If we say that for each Choose User button we are setting the row number as the tag and assuming that you don't have sections so everything will happen in section 0 we could do.
- (void)hitChooseUser:(id)sender
{
// Do whatever you want for when a user hits the `Choose User` button
// Code......
// Then do this at the end or whenever you want to do it.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];
// Also assuming you have created you have created you UITableView correctly.
[self tableView:myTableView didSelectRowAtIndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Do whatever it is you want.
}
I also found this link that may help you Manually call didSelectRowatIndexPath
You could also disable the user interaction with the cell itself by setting userInteractionEnabled: to NO for each cell in cellForRowAtIndexPath: so didSelectRowAtIndexPath: will only get called when you want to call it manually.
Do not call didSelectRowAtIndexPath: It is a UITableViewDelegate method and, where possible, should be used as such (meaning let the UITableView send messages to it). In addition, it creates an unnecessary dependency on UITableView implementation.
That being said, in order to achieve shared behavior that is performed either on button click, or on row selection, refactor it out into a common method that is not coupled with UITableViewDelegate
For example:
-(void)doSomethingCommon {
//do shared code here
}
-(void)chooseUserButtonPressed:(id)sender {
[self doSomethingCommon];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self doSomethingCommon];
}
And if your UITableView shows more than one of these rows, for which you depend on knowing which corresponding model object is related to the cell, than you can use the tag property on UIView subclasses (usually something in your cell) to mark the row that the object is shown in.

tableviewcontroller within container view controller: programatically selecting uitableviewcell, highlighting blinks

I am trying to programatically highlight a table view cell and trigger the selection logic by doing the following
NSIndexPath*indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
The row highlights only for a split second. I want it to stay highlighted until I select another row.
I tried adding these lines
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath: indexPath];
cell.highlighted = YES;
but when I did this, the highlight remained even when I clicked on another row and did not go away until I clicked the first row again.
Any ideas?
Try calling selectRowAtIndexPath but not didSelectRowAtIndexPath. I believe the latter is called as a result of the former. If your delegate deSelects the last selected index path in didSelectRowAtIndexPath, then the double call would result in deselecting what you had just selected
seems like the issue was because I was calling the code from viewDidLoad, I moved it to viewDidAppear and now its fine

How to make a UITable to highlight its 5th row when we start the app?

I am using a splitviewcontroller. When I select something in the table the row is highlighted and it is shown in the detailed view. I have also provided an option to change the contents in the detailed view by scrolling.
When I start I want the the 5th row to be highlighted by itself, how can I do it?
Check out the following UITableView method:
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition;
I was using the above function from the start. But the app was crashing when I wrote this code into the viewDidLoad.
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:5 inSection:0];
[self.tableView scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
There is no data loaded into the UITableView instance. You can't select a row that doesn't exist. This was the reason it was crashing. And yes, this is the function that will help us do it.

Resources