How to preserve the value of a uitextfield during a scroll - ios

I was having troubles using the dequeue mechanism in my tableview, i have a custom cell with a uiTextField.
When a put some value on it and do a scroll, the value of the TextField goes to another cell.
Anybody can help me on it ?
Thanks guys.
Here is the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyPedidoItemCell";
PedidoItemCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (!cell) {
cell = [[PedidoItemCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Produto *produto = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.lblNome.text = produto.nome;
cell.lblCodigo.text = produto.codigo;
cell.lblFuncao.text = produto.funcao;
return cell;
}

When you call dequeueReusableCellWithIdentifier it may return a cell that has scrolled out of view but still contains data in the UITextField. If you don't clear the content of the UITextField or set it to the proper value for the row, you may see unwanted data.

The code you showed is using CoreData to load data for cell, but you mentioned that you don't store the data anywhere.
I suspect that the you are getting object with no data from your fetchedResultsController because you did not store any data.
So quite possibly the produto is nil and you are not setting any values on cell.
Eventually the cell you updated manually gets reused and you see the text again.
You need to first store the data that you typed into the UITextField before you can retrieve it from core data.

Related

iOS scrolling tableView reusable cells reload

I am working with tableviews in iOS. Reusable cells are reloaded when scrolling.
So, when updating -for example- textfields inside a cell, it disappears once scrolling over. I solved it by using an Array that saves all texts in all cells, but I wonder if there's a better way to solve this issue.
Thanks.
Using String array you have to store data of all textfields in tableview.
Use delegate methods of UITableView to implement more efficiently.
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell * mc = (MyCell *) cell;
names[indexPath.row] = mc.myTf.text;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell * mc = (MyCell *) cell;
mc.myTf.text = names[indexPath.row];
}
Here, MyCell is the custom cell which has UITextField. name[] is the NSString array declared at class scope like NSString * names[20].
What you are describing is how tableviews are meant to work! The tableView is a display, not a store, and the reusable cells are only those currently displayed
You are right to use an array (or collection) to hold the data and just use the tableView to display it
for memory management (to releasing memory) tableview remove cell memory which are not displaying in current screen its only keep those cell in memory which are currently displaying on screen so you have to store that text separate from tableview.
You issue can be because of multithreading. If you are reloading data from a GCD operation or any NSOperation(different thread), then you have to use the below code to get the handle to main thread
dispatch_sync(dispatch_get_main_queue(), ^{
//perform the reload activity
});
Yes you are doing right, as cells are reused you need to save your data, something like this -
1 . Have an array to hold your data.
2 . Update your array whenever you make any change in your textFields, so that your UI and data are in sync.
Use this array to populate your tableView.
You need to define the cellIdentifier as unique. Then each cell created with unique identifier.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%dR%d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
//your logic here
}
return cell;
}

Is cellForRowAtIndexPath called when you use a custom cell?

I am using a custom cell class in a tableview controller.
When I include a statement in the tableviewcontroller in cellForRowAtIndexPath NSLog(#"method called"): it does not seem to get called.
Is it possible that this method is not called when you have a custom cell?
Edit:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cell for row at index path called");
NSDictionary *item= [self.getItems objectAtIndex:indexPath.row];
//This sets place in storyboard VC
IDTVCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.item = item;
if (cell == nil) {
cell = [[IDTVCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"Cell"];
}
return cell;
}
cellForRowAtIndexPath is not called if no rows are returned.
-tableView:cellForRowAtIndexPath: is not getting called
That is what happened in my case.
It can also not get returned if you reload table on wrong thread and in certain other scenarios.
cellForRowAtIndexPath: not called
However, a custom cell per se does not cause this..
To answer your question - Yes, it is.
There could be n-number of reasons why cellForRowAtIndexPath: is not getting called. This may be because delegate / dataSource is not set or UITableView frame is not set... etc. etc.
You should easily find a solution with more online research and closure look at your code.

Disabling a cell in didSelectRowAtIndexPath not working?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.userInteractionEnabled = NO;
}
I use the above code to disable a cell after a user clicks on it once. The problem I've run into is that when a cell is added to the table, that new cell is disabled, and the previously disabled one isn't anymore.
How can I fix this problem?
Cells get reused as the user scrolls the table. You need to keep track of which rows the user has disabled so in your cellForRowAtIndexPath you can set the userInteractionEnabled property (to YES or NO as needed) for every cell every time it is requested.
Update - more details.
You need to keep track of which index paths the user has selected. Add an instance variable of type NSMutableSet and add each indexPath to this in your didSelectRow... method.
Then in your cellForRow... method you need to check if the current indexPath is in the set or not. Based on the result you set the cell's userInteractionEnabled property:
cell.userInteractionEnabled = ![theSelectedPathsSet containsObject:indexPath];
where theSeletedPathsSet is your NSMutableSet instance variable.
This solution assumes the rows and sections in your table are fixed. If the user can do things that results in rows being added, removed, or moved, then you can't simply track the index paths. You need to use some other key to know which rows have been selected.
Are you using dequeueReusableCellWithIdentifier in your cellForRowAtIndexPath?
You should have something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *reuseIdentifier = #"myTableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (!cell) {
cell = [[ArticleTableViewCell alloc] init];
}
// customise cell here (like cell.title = #"Woopee";)
if (self.selectedCells containsObject:[NSString stringWithFormat:#"%d", indexPath.row]] {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.userInteractionEnabled = NO;
}
return cell;
}
Expanding on the other answer, you can keep track of whether a specific cell has been previously selected (are therefore should be disabled) by doing something like this with the above:
Declare a property like #property (nonatomic, strong) NSMutableArray *selectedCells; then:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
[self.selectedCells addObject:[NSString stringWithFormat:#"%d", indexPath.row]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.userInteractionEnabled = NO;
}
My laptop is about to die, but if it crashed you should look at the code the initialises the cell (alloc and init) or keep what you had before there.
You need to keep a record of which cells have been disabled. You could store the indexPath of the selected cells in an array and then use that to determine which cells should be active and not active in your cell:forRowAtIndexPath: method.

dequeueReusableCellWithIdentifier does not work

I want to load around 6000 - 8000 rows in a UITableview. I get the data from the server using a async call and when I get the data I call
[tableView reloadData]
This is to refresh the table view . But because of some reason my app gets stuck and freezes .
When I debug , I found that cellforrowatindexpath is called 6000 times (on main thread) and
dequeueReusableCellWithIdentifier always returns null .
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CDTableRowCell *cell = nil;
// Create and Resue Custom ViewCell
static NSString *CellIdentifier = #"CellIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// got into render/theme objec
if(cell == nil){
cell = [[CDTableRowCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// MODIFYING CELL PROPERTIES HERE FROM AN ARRAY
// NO HTTP CALLS
}
Also, tableview starts reusing cell once I start scrolling but before that I never always create a new one.
Any clue why this strange behavior ???
try like this,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier =#"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
return cell;
}
The method in your question is not a table view datasource method. The datasource method has the table view as an argument. The method you have written is one that can be used to obtain a cell from the tableView itself, not to obtain a new cell from the datasource.
I don't know how often that method is called but overriding it is almost certainly not what you want to do.
I'm guessing you have subclassed a uitableview to be its own datasource? If so, you need to have the code in your question in the datasource method tableView:cellForRowAtIndexPath:, and not override the method as you have now.

Table Populated by Core Data doesn't Display Properly

I'm populating a TableViewController given an array of NSManagedObjects of class "SampleClass". Although the number of objects in the fetched array returns correctly (i.e. if the table is to display 59 objects, 59 rows are created), the other parameters for the cell are "glitchy" to display.
For example, where there should be a title set by object.name, "null" until you click on the the cell, select another cell, and then come back to the initial cell.
I've tried `[tableview reloadData]' in the view will appear, and it still takes too long to load the data. Is there a better way to fill in the cell instead of:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
Class *classObject = [dataArray objectAtIndex:indexPath.row];
cell.textLabel.text = [classObject name].....
where dataArray points to the NSMutableFetchedArray from a coreData call
Note: the simulator misses filling more of the cells than the actual iPad. once another tab is selected however, all the cells display correctly when you return to the tab.`
You may want to look into NSFetchedResultsController
http://developer.apple.com/library/iOS/ipad/#documentation/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html
It is a special class which is meant specifically for populating a table with results from a core data query.
In the past when using core data I have always used this class over other means.

Resources