UITableViewCell error call tableView:didSelectRowAtIndexPath: - select

I want to access the UITableViewCell that is after the one that is selected and select that one,
int b = lastIndexPath.row + 1; //lastIndexPath references to the current selected cell index path
NSIndexPath *myNextIndex = [[NSIndexPath alloc]initWithIndex:b];
[self tableView:table didSelectRowAtIndexPath:myNextIndex];
so up to this point everything works fine, the b value is 2. but when the tableView:didSelectRowAtIndexPath: and I want to get the value of i,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int i = indexPath.row;
//some other stuff
}
I get the value 81809923 for i, but the value of i should be 2.
I don't know why this would happen. if anyone has any idea please help.
thanks

Positions in a UITablleView are keyed by both section and row (even if your table only has a single section). The iOS SDK adds a utility method specifically for the purpose of making it easier to work with table views.
In this case, you would use it like:
NSIndexPath* myNextIndex = [NSIndexPath indexPathForRow:b inSection:0]; //call 'retain' if you need to
As for your 81809923 value, that is probably random garbage that happened to be in memory, since your original code does not assign any value to the row field of the NSIndexPath.

Related

How to disable UITableViewCell selection one by one?

I am creating a table view based iPhone application, Where i need to disable one by one entire table view cell.
The requirement is like -
Case-1 :-
Initially only first table cell row should be user interaction enable, rest should be disable. We can easily do this to make indexPath.row 0 enable in CellForRowAtIndexPath method.
Case-2 :-
If User will tap on First cell and when again he will come back then First cell will be disable and second cell should enable(rest table cell will be disable at this time after second cell).
Case-3 :-
Again if user will tap on second table cell and come back to this table then apart from Third cell, others should be disable and so on...
It means i need to disable one by one all the table cell in serial order.It is possible by setting index but it won't be the proper way to do this. So, can you please suggest me what condition i need to give for this ? Please suggest me for further proceeding.
Thanks.
Just maintain an instance variable which holds the cell number that should be enabled.e.g. enabledCell.
Initialize enabledCell to 0. In didSelectRow increment enabledCell and reload the tableView. In cell for row at indexPath only enable the cell if the indexPath is same as the enabledCell value.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// write code to dequeue or create new UITableViewCell here
// then check if index is same as the cell that should be enabled
if(index.Path.row == enabledCell)
cell.userInteractionEnabled = NO;
else
cell.userInteractionEnabled = YES;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//Assuming you have number of rows stored in variable numberOfRows
enabledCell++;
if(enabledCell == numberOfRows)
enabledCell = 0;
[tableView reloadData];
}
There are many ways to do this (from now on, I'm a assuming a linear table view with n rows and only one section).
For example, you can add a BOOL enabled property to your cell model object. In your controller's didSelectRowAtIndexPath: check that property and do nothing if it's set to NO. If it's set to YES then navigate to the appropriate page and exchange the enabled property with the one at index position i + 1 (or position 0 if it's the last entry and you want to cycle).

Populating UITableView row 0 static and the rest with NSArray

In one section of my app I have a UITableView which is working fine right now. I would like to set row 0 cell.textLabel.text to #"Some string". Once row 0 has been set I would then like to load the rest of the rows from an array. Currently on load my array populates the table view but I'm trying to set row 0 as a sticky. The closest example I can think of is a forum topic that is set to stay at the top. My array is constructed of returned data from a web service call.
It's been a while since I've messed with table views, and I'm having a blank on this one.
The table view is 1 section, and I get the rows by counting the elements in the array. Since I would like to create an additional cell (row 0) I would call [array count] + 1. I don't know if this approach is the best one which is why I'm reaching out to the community here.
Any insight or a shove in the right direction would be great at this point.
You're on the right track:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array count]+1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if ([indexPath row] == 0) {
// Code for first
[[cell textLabel] setText:#"First cell"];
} else {
[[cell textLabel] setText:[array objectAtIndex:[indexPath row]-1]];
}
return cell;
}
If you want the top of your table to be "sticky", why not consider using that string as a section header or title? In this case, the header stays visible at all times until the next section (e.g. if you had two sections, that is) is fully on the screen.
In any event, in one of my current projects I'm required to do roughly the same thing that you're doing and I have a static string being returned in row 0 (which scrolls off the top of screen when the table view scrolls down).
And in my UITableViewDataSource method, I always add one for the static cell to the number of objects in my array and in my "cellForRowAtIndexPath:" method, I increment the row by one when the indexPath.row is not zero. And if it is zero, I return my static string.
And dark_knight provides some nice sample code that illustrates what I was describing to you. So +1 to him/her.

indexPath Adjustment iPhone

I have a UITableView that, under certain conditions, needs to have something added to the top of it. All data (except for what is inserted at the top of the UITableView under certain conditions) is brought in from an array.
Because everything is brought in from an array, I need to modify the indexPath that fetches those array objects each and every time the method - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is called. If I try to create a local variable and update the local version of indexPath.row, it tells me it is read only.
What would be the best way to implement this?
Drawing below (this is not intended to be code, but a drawing of the table view):
(REGULAR SITUATION) (3 lines)
array objectAtIndex:0;
-----
array objectAtIndex:1;
-----
array objectAtIndex:2;
etc. etc
(MODIFIED SITUATION) (4 lines)
blah blah modified insertion text here
-----
array objectAtIndex:0;
-----
array objectAtIndex:1;
-----
array objectAtIndex:2;
etc etc
Thanks in advance.
Why not just add your new item at the start of your array?
// Create a mutable copy and add the item at index 0
NSMutableArray *mutable = [myData mutableCopy];
[mutable insertObject:newItem atIndex:0];
// Then store the new array and reload the table
[myData autorelease];
myData = mutable;
[self.tableView reloadData];
Then you don't have to do anything funny at all with index paths :)
THIS is a great tutorial that addresses your issue.
Use
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
OR
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
Return the String/View as something or empty depending on the condition that you use while deciding when to show it or not.
Don't go down that path. Just use the tableHeaderView property of UITableView to add something on top of the table. It will scroll just like a UITableViewCell.
self.tableView.tableHeaderView = aView;
To remove it, just set it to nil.
If you insist in this method, just keep a BOOL around to tell you in which state you are and if you need the extra line just subtract 1 from indexPath.row, like
[myArray objectAtIndex:indexPath.row-1];

Referencing UISwitches within UITableCells

I have a table view which I'm using for some settings in my app. The tables cells are all default (no customisation at all), and simply contain some text for their label and a UISwitch for the accessory view.
My problem is that I need a reference to the switch so that I know when it has been switched on and off.
Currently I am setting the 'tag' property of the switch to be that of the cell's index within the table (grabbed from [indexPath row] in tableView:cellForRowAtIndexpath:).
This is fine when you only have one Section in your table, but I am now adding a new section. The problem is that they are both 0 based indexed so the switches in each section will end up reusing the tags - which isn't good.
Any suggestions on a better way to achieve this?
Thanks.
If you know roughly how many sections and rows you will have, like oh, say, not more than 1 million rows per section, just hash the section and row like this:
const int oneMillion = 1000000;
int tag = (section * oneMillion) + row;
slider.tag = tag;
Then, to figure out the section and row, reverse the logic:
int tag = slider.tag;
int row = tag % oneMillion;
int section = tag / oneMillion;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow: row inSection: section];
Now get the slider that is in the cell in that section,row of the table
UITableViewCell *sliderCell = [tableView cellForRowAtIndexPath: indexPath];
UISlider *slider = [[sliderCell.contentView subviews] objectAtIndex: 0];
This assumes the slider is always the only view in the contents of the cell.
This method is a bit longer than some of the other suggestions above, but it keeps you from having to cache references off to the side.
For each cell, set a delegate link back to the table view controller, and also some kind of row reference ID - then wire the switch to a cell IBAction method, that calls back to the delegate with the reference ID for that cell.
What you can do is either have an Array of arrays or a dictionary, key it by the section number (or in case of the array they will be in order of the section numbers), now to retreive a switch all you do assuming you know the section and the row number
UISwitch *switch=[[switchArray objectAtIndex:section] objectAtIndex:row];
or if you have a dictionary
UISwitch *switch=[[switchDictionary objectForKey:section] objectAtIndex:row];

iPhone SDK: Inserting and updating a UITableView with a new row

I have a tableView that needs to be updated after information has been inserted from another view. If I perform a
[self.tableView reloadData];
The very next time I insert more information in another view and try to reload the table, all the currently visible rows are duplicated.
In other words, when I start up the app I have:
tableView:
Row 1
Row 2
Then I submit some information that will also show up in the table and suddenly I have:
tableView
Row 1
Row 2
Row 3 <- info I just added
Row 1
Row 2
My numberOfRowsInSection implementation looks like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [ItemsController sharedItemsController].count;
}
My cellForRowAtIndexPath implementation looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ItemsController* controller = [ItemsController sharedItemsController];
NSMutableArray* recentItems = controller.listOfRecentItems;
CustomCell *cell = nil;
NSUInteger row = [indexPath row];
if( row < recentItems.count )
{
Items* item = [recentItems objectAtIndex:row];
if( recentCellData == nil )
recentCellData = [[NSMutableDictionary alloc] initWithCapacity:[indexPath length]];
if( [recentCellData count] > 0 )
cell = [recentCellData objectForKey:[NSString stringWithFormat:#"%d", row]];
if (cell == nil) {
UIViewController * view1 = [[UIViewController alloc] initWithNibName:#"CustomCell" bundle:nil];
cell = (CustomCell*)[view1 view];
[recentCellData setObject:cell forKey:[NSString stringWithFormat:#"%d",row]];
}
// do some other stuff here
}
// Set up the cell
return cell;
}
What's the best way to update the table and avoid duplicating the currently visible rows.
Thank in advance for all the help!
The error isn't in how you're reloading the table, it's in how you're providing data to it. Set a breakpoint in the data source methods and the method that adds new rows to see where you're going wrong.
You'll only end up with five items if tableView:numberOfRowsinSection: returns 5. Thats the simple answer to your question, but I see other problems here. I'm wondering why you have this test: row < recentItems.count. Is that array the same thing as [ItemsController sharedItemsController].count? You really need to be using the same array for both methods.
(Also, it's not a syntax error, but you shouldn't use the property syntax for things that aren't declared as properties. You should write [recentItems count] instead.)
I'm also confused by the code you use to set up the cell. Cells are meant to be reusable. That is, you create one cell, then reconfigure it every time in your implementation of tableView:cellForRowAtIndexPath:. Your code creates a cell for each item in your list. This is very memory-inefficient, and will likely crash your program due to insufficient memory on the iPhone if you keep lots of cells in memory like this.
The recommended approach is to call dequeueReusableCellWithIdentifier:. If that returns nil, then you set up a cell using the initWithFrame:reuseIdentifier: initializer. The table view is very smart, and will only ask you to redraw the cell when it needs you to.
Your recentCellData dictionary looks really shaky to me, too. What if you insert an item after the item with key #"2"? All the items with key #"3" onward will need to be shifted one element to the right to work the way you expect. That's a ton of bookkeeping that seems rather unnecessary to me. If you really needed something like this -- and to be clear, I don't think you do -- why wouldn't you use an NSMutableArray, which is much easier to use?
I added a bit more info above.