Is there a way to get access to a UITableViewCell that is not currently on screen? I'm trying to update rows that are currently not in view. I am using this collapsable/expandable rows for a UITableView in one of Apple's example codes. I use this:
for (NSInteger row = 0; row < totalRows; row++) {
NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:section];
OrderTableViewCell *cell = (OrderTableViewCell *)[_tableView cellForRowAtIndexPath:path];
cell.CheckmarkButton.selected = YES;
cell.Symbol.isSelected = YES;
}
My totalRows is correct in that I get the number of rows from the TableView. So I thought I could use that, loop through all the rows, and set some values. However, if I check the state of the rows, the ones that are currently on screen have values and I can change them, but the ones off screen are null and cannot be set. Is there a way I can get around this? Thanks.
Depending on what you want to update you could just update the ith entry in a backing collection.
For example you could have a collection that stores bools corresponding to CheckmarkButton selected. In your loop you could set myArray[row] = YES. In cellForRowAtIndexPath you can do cell.CheckmarkButton.selected = myArray[indexPath.row].
If you want to maintain multiple items for each cell then myArray in the above example could contain instances of an object that holds values relevant to the ith cell.
Well why do you have to update a cell like that... If the cell is out of view, to save memory the system unloads it, and since its not in the view there is no need for you to update the cell directly, rather you should have the state be reflected in such way that when cellForRowIndexPath is called by the table view to load the cell the desired look is shown... The only reason youd want to do what you are doing is if the cell is showing and you need to update the cell, for the user... Even then you can still set your state and call the reloadRowsAtIndexPaths instead of manipulating the cell directly... Hope that helps
Related
I am trying to delete a row from UITableview outside the delegate method. I am calling a method when I click a button inside a table cell and trying to delete the row inside that method.
Here is the function I am using
UIButton *btn = (UIButton*)sender;
int tag = btn.tag;
UITableViewCell *buttonCell = (UITableViewCell*)[[btn superview] superview];
NSIndexPath *indexPath = [self.msgTbl indexPathForCell:buttonCell];
[deleg.rmessages removeObjectAtIndex:buttonRow];
[self.msgTbl deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];NSInteger buttonRow = indexPath.row;
[self.msgTbl reloadData];
Using this one or two rows get deleted but after that its crashing giving exception
Number of rows before and after deletion must be same
How can I do this in ios?
Thanks
Your problem is that the data that is being taken to populate your table isn't consistent with the table after deleting the cell. Make sure your dataSource methods provide the correct data after doing this (for example, if it is an array of objects you are using to populate the table, you must remove the object from the array as well)
The root issue is that this method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
Must return the correct number of rows, and it isn't. When you remove the item from deleg.rmessages, is this the same object that is being used to supply the return value of the above method? (Something like [deleg.rmessages count]?)
Also, in my experience that exception often gives you more details, in particular:
How many items it had before
How many were added/deleted
How many it expects to have vs. how many it does have after the reload
Do you see anything like this being mentioned? If so, it would be worth including in your question.
Sidenote:
It's a bad idea to rely on:
UITableViewCell *buttonCell = (UITableViewCell*)[[btn superview] superview];
To return the UITableViewCell. You appear to assign the tag of the button to a local variable, but never use it. (Maybe this would be a good place to store the index of the UITableViewCell, and then subclass the cell to maintain an ivar to the button?) This is only part of the problem.
How do I get the cell for an indexPath which is not currently visible in the table? (cell is out of range)
Code for getting my cell:
NSString *name = [[(ELCTextfieldCell *)[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] rightTextField] text];
-cellForRowAtIndexPath... returns nil because the cell at the required indexPath is out of range. So how do I get the correct cell and not nil?
The UITableView only keeps the visible cells. If you need one that isn't visible you have to call the tableView:cellForRowAtIndexPath: of the UITableView dataSource. So, if self is a class that is the dataSource:
UITableViewCell * cell = [self tableView:table cellForRowAtIndexPath:indexPath];
This is not how it works. You need to grab and store the information as soon as it is entered or changed. It may easily get out of scope and you cannot guarantee your cell lives long enough. Well, technically you can hold onto it (and always return the very same cell for the same index path), but I'd question that design.
UITableViewCells are made to be reused/recycled in a way that the users won't need to create more cells than the number of visible ones.
You usually don't need to access a cell that is not visible. It should be enough you access your datasource and get/set the correspondent data there. Cells are for showing some state of the datasource. Not the datasource itself :)
Edit:
You said you need some information (text) from one cell above, right? If you use cellForRowAtIndexPath: method the cell will be recreated but you might not get the text that was in the textfield. The reason? because probably you didn't save it somewhere else. If you did save it, then access that directly instead of going through the cell.
In continue to #Raphael's answer, Here is the (working) swift 3 solution:
UITableViewCell cell = self.tableView(self.tableView, cellForRowAt: indexPath)
Is the information to fill your table coming from an array? Could you not pull that directly out of the array at 0 index, same as your cellForRowAtIndexPath would presumably retrieve and fill that cell when it is displayed?
i am getting images with messages from .net webserver by giving xml input.
that's working fine.
i am sending request for every 3 sec and if any new messages and images are there i just add those messages and images to the array and reload the table view.
That is also fine,But what i need is when i reload table view when ever there is new messages that will be displayed on table view by smooth scrolling the existing row.
same as twitter.
can any one please help me.
Thank u in advance.
if you know the indexPath of newly added row , you could use the below function of UITableView to scroll upto new row with animation (smooth effect).
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated
Instead Of completely reloading the table, you should call insertRowsAtIndexPaths:withRowAnimation:
The second option will let you specify how you want it animated
(this will also be much more efficient than reloading all the data every time)
You can do something like the following:
(this makes the assumptions that recievedImageFrom server will be called after the data has already been loaded into the data source object. Also, myDataSourceArray is the array where the data is being stored for the table and myTableView is the UITableView.
-(void)recievedImageFromServer
{
NSUInteger row = [myDataSourceArray count]-1; // This can also be set to 0 if you want
// to insert at the top of the table
NSIndexPath* newIndex = [NSIndexPath indexPathWithIndex:row];
[myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndex]
withRowAnimation:UITableViewRowAnimationTop];
}
It will then request the cell from its data source.
thanks in advance
i want to read cell value from tableview but without selecting any cell.
let me explain first
in my table view each cell have some value when tableview is drown fist time this all value is coming from database.
then later through didselectedRowAtIndexPath for example i select first cell value and take it in label in another view and change it a when i click save button on new view then my new value is coming back in first view in table view cell correctly this all operation is correctly working.
but my problem is that after changing some cell value i want to read all the data that display on table view cell but without selecting any cell in didselectedRowAtIndexPath or any other method i read this cell value on my save button on this view and after read this value i again save it in database
Geez, I think if I were you I'd go the other direction. You surely have a data structure of some sort (an NSArray, quite likely) that you used to populate your tables with data in the first place, right? Why not just get it from there, rather than getting your mitts on the UITableViewCell and digging into its view hierarchy to find the label you want?
The didselectedRowAtIndexPath method is just a means to tell you what point in your array to read data from. You have to create an array of some sort to build the table from. If you know you want to read data from the first cell, simply read it directly from the array populating your table. Doing this at the end of viewDidLoad would be appropriate.
Try...
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if its a custom cell use
CustomCell *cell = (CustomCell *)[tableView cellForRowAtIndexPath:indexPath];
NSLog("%#", cell.property):
You can get cell for only visible rows without clicking them as
NSArray *visibleRowsArr = [tableView indexPathsForVisibleRows];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:[visibleRowsArr objectAtIndex:0]];
and from this cell you can get values for a tag which you have to specify while creating a cell.
in iphone application.
I'm trying to get indexPath.row value (out of didselectedrowatindexpath method) to do something on the basis of row selected in programmatically created tableview.
i need to access indexpath.row out of didselectedrowatindexpath method where if/else will define the action on the basis of indexpath.row.
there are 7 cards images in application and one [menu list]table view. whenever user will click on row of table view,then need to touch the image
I'm trying this code to get the IndexPath.row value. The problem is indexPath.row value is not updating everytime. It's just taking the old value. Please sugggest how to solve this issue.
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
NSUInteger nSection =[myTableView numberOfSections]-1 ;
NSUInteger nRow = [myTableView numberOfRowsInSection:nSection];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:nRow inSection:nSection];
NSLog(#"No of sections in my table view %d",nSection);
NSLog(#"No of rows in my table view %d",nRow);
NSLog(#"Value of selected indexPath Row %d", [indexPath.row]);
NSLog(#"VAlue of Array arrOperationChk %d",[arrOperationChk count]);
}
This code appears to respond to something (the table?) being touched. You then ask the table how many rows it has in its last section and create an indexpath to that.
The table caches the number of rows in each section. If you have changed the number of rows, you need to tell the table, either by calling -insert/deleteRowsAtIndexPaths:withRowAnimation:, or by calling -reloadData. Otherwise the table has no way to know that it needs to re-query its datasource (which you provide).
Unless I'm reading this code wrong, aren't you just getting the index path to the last cell+1 of the last section? I wouldn't expect that to change.
If you want to get the selected cell, use the
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
method in your UITableViewController object.
As other people have said, there's nothing in your code that would change the indexPath variable you've just created.
Also, the syntax [indexPath.row] looks wrong - you don't need the square brackets there unless you're calling a method. When you use the dot syntax like that on a pointer in Objective-C, you don't think of it as a method call (even though there is one, implicitly), but rather as a pseudo-instance variable as of a struct.
What is your big picture goal? If we understood what you are trying to achieve / what is the desired behavior, maybe a more useful answer will arise.