UITextField values inside UICollectionView cell in swift - ios

I have UITextField and an ImageView inside UICollectionView cell. It loads data from web service. The user can input data inside the text field and have to submit it. My problem is, when I scroll the collection view, the entered value in one text field in a cell got messed up with other text field values from another cell, and it displays wrong values.
my steps(suppose I have cells A, B, ......., k)
1.entering values
Cell A Textfield= 12
Cell B Textfield= 13
2.scrolling down
(I haven't entered anything in cell F Textfield, though it shows 13)
3.scrolling back to where I entered values
Cell A Textfield= 12
Cell B Textfield= (blank)

You can solve this problem by keeping the values of UITextField in an Array. Whenever you are entering value to UITextField and dismissing keyboard,then save that value to array at the same cell index value in array and when you scroll your collectionView, the textfield value should entered from array and it won't misplace value.

UICollectionView and UITableView reuse a handful of cell objects as you scroll. This helps with memory management. It also means that when you populate one text field on a cell, that text field's cell will get reused for a different row as you scroll, so if you don't reset the text field's content, you'll see the same data showing up for the wrong rows.
The solution is that your "source of truth" (aka model) must always be separate from your UI. So when the user types something in a text field, your model (perhaps an array of strings?) should be updated accordingly. Then when the user scrolls, you must use tableView:cellForRowAtIndexPath: or collectionView:cellForItemAtIndexPath: methods to populate the cell with the appropriate data. If there is no data, you must clear any data that may have been left over from another row whose cell got reused.
Other opportunities you'll have to deal with cell reuse include the willDisplayCellForRowAtIndexPath method on UITableViewDelegate, or prepareForReuse on UITableViewCell. Collection view objects have corresponding methods as well.

As far as I can understand from question I think the problem is, you are not updating values every time - cellForRowAtIndexPath function gets called on scrolling.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
what you need to do to resolve this issue is "You have to store all the values you have entered in your cell's textField and whenever above datasource method gets called for UITableView, updated cell accordingly".

Related

iOS Voiceover: Focus selected cell and not the first row

I trying to make my app accessible, in my interface I have a UILabel and a UITableView, the tableView have a selectedRow. The selectedRow is the row in the middle of table view, for example is the row 50 if I have 100 row.
My problem is when I swype in screen to go to my next element, in this case when I go from label to tableView, the focus go to the first index and not to my cell was selected.
How I can fix that?
Assuming you have only a label and a table view, the problem boils down to keep in mind the latest position of the cell when you move from the label to the table view.
The following algorithm may be used to solve this problem :
Create a temporary index path variable (tmpIP) containing the index path of the selected cell.
When the label loses the focus, the table view selects the cell with the latest tmpIP index path. The variable value is nil if no cell was selected before the label selection.
Take a look at the UIAccessibilityFocus informal protocol to handle the focus of an accessible element.

How to not reuse UITableViewCell and keep cells in memory after they disappear from the view?

I have a "not so big" dynamic tableView with a number of rows that can vary between 10 and 20.
I used Storyboard and created 4 different cell prototypes which all have their own identifier. Most of these cells have UITextFields in them and the user will enter information such as e-mail adresses etc...
I use dequeueReusableCellWithIdentifier: in tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) to create my cells.
However whenever I scroll my tableView I can see that the appearing cells get the data from upper cells, because cells that disappear are enqueued for reuse.
Given the fact that I have a limited number of cells, I would like to get rid of the reusing feature and just have my set of cells with their own data inside. When I scroll down I see cells that correspond to the lower cells, and when I go back up I see again my upper cells.
How can I do that?
and how can I then create a cell that corresponds to a prototype from the storyboard without using dequeueReusableCellWithIdentifier: ?
I have already searched among similar question here in StackOverflow and tried to keep an array of my cells and just return the correct element if it already exists from tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) but nothing worked so far
You are overthinking this a bit. If you think about what dequeueReusableCellWithIdentifier: does, it just grabs a cell that it finds with that specific identifier. If you want every row to have it's own unique cell that is not used by any other row, just give each row it's own identifier. The simplest way would be to just to stringify the indexPath row, or both the row+section if you have multiple sections.
Something like this should do it:
let cellIdentifier = String(indexPath.section) + "-" + String(indexPath.row)
In these cases I will typically create what would be the content of the table view cell in its own view controller or custom view, something like "SignupFormViewController", and store that as a property on the view controller that is managing your table view. In your case this could also be multiple view controllers of this type in several properties or an array. Then dequeue your cells as normal but treat them as dumb containers to which the view controllers' views are added as subviews. Then you'll just to have tie up all the loose ends—removing the view from the cell when the cell dequeued, not adding a view if the identical view is already a child of the cell, constraints to match cell size, etc.

Multiple cells got affected after calling cellForRowAtIndexPath

I have a UITableView, and I want to change text color of the selected row. But I see every other 15 row got affected along with the one I clicked. This is tested under the master-detail sample project.
if let indexPath = self.tableView.indexPathForSelectedRow(){
self.tableView.cellForRowAtIndexPath(indexPath)?.textLabel?.textColor = UIColor.redColor()
}
I checked cellForRowAtIndexPath value in debug session, it seems returning only one object, how come other cells got affected too?
Cells are reused - almost certainly you are not resetting your cells to a base state in prepareForReuse and configuring them correctly on each call to cellForRowAtIndexPath.
When you look at a table view that can display some number of cells at once, typically there will only exist one more cell than can be shown. When a cell is moved off the screen it is placed in a pool of cells for reuse. Just before a cell moves onto the screen it is configured by you, in cellForRowAtIndexPath. If you have configured something in the cell and you do not configure that explicitly every time you return a cell from cellForRowAtIndexPath then that configuration persists in the cell that is in the reuse pool. The function prepareForReuse is also called before each cell is reused - if you have subclassed UITableViewCell then you can implement this function to return the cell to a base configuration, so that settings like text color do not unexpectedly affect multiple cells.
This approach makes it possible to scroll through an entire table view smoothly with a minimum amount of memory used. It is an expensive operation to create and destroy cells every time one disappears and a new one is required.
The simplest fix is to always set the text color in cellForRowAtIndexPath - either to the base color or to the special color you want in some cells.

Can you store state in a custom UICollectionViewCell? Or can the state get erased (like when the cell scrolls off the screen)?

If I create a UICollectionViewCell subclass like:
class StudentCell: UICollectionViewCell {
var student: Student?
}
And in my controller I implement UICollectionView's didSelectItemAtIndexPath and set the variable:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
if let studentCell = collectionView.cellForItemAtIndexPath(indexPath) as? StudentCell {
studentCell.student = self.someStudent
}
}
When I click on the cell it should set student, but if the cell is scrolled off screen it seems like the whole cell might get wiped and when it comes back on screen it would need to rebuild itself in cellForItemAtIndexPath.
The problem I have is that I have a UICollectionView with cells that do not scroll off the screen that I'm storing data in. Because they don't leave the screen I assume they should not get wiped, but one of the cells does not seem to keep it's variable, which makes me think maybe it's getting wiped and I may need to move the state outside of the cells to a dictionary or something and in didSelectItemAtIndexPath instead of setting the variable in the cell I'd set the dictionary. Whenever I need to access the data instead of asking the cell for it I'd look it up in the dictionary.
But either way, I was wondering if it's possible (or a bad idea) to set it in the cell or not.
Yes, cells in both UICollectionView and UITableView can (will) be reused at the systems discretion and should not be used to store state information, only display information. Specifically, both views will reuse cells when they are scrolled off-screen, but there's no guarantee this is the only time they'll be reused. The usual way to handle this is to define some kind of cell data object which stores the data for each cell (visible and not) and refresh the cell view from that as needed/requested.
Tables display their data in cells. A cell is related to a row but it’s not exactly the same. A cell is a view that shows a row of data that happens to be visible at that moment. If your table can show 10 rows at a time on the screen, then it only has10 cells, even though there may be hundreds of rows with actual data. Whenever a row scrolls off the screen and becomes invisible, its cell will be re-used for a new row that scrolls into the screen.

UITableView change detailText on already created cell

I have a UITableView, to which I add cells via UIButton. On creation the cell gets its textLabel & detailTextLabel from 2 arrays. However, if an item with the same Title already exists in the table, I want to change the detailTextLabel.text of the existing cell without adding a new cell.
So is there a way to update the detailText of a certain UITableViewCell when it was already created with some value?
Maybe I should just remove the old one and add new?
Creating of a UITableView cell should be just that, creation and not population of data, since we re use cells we should always assume the cell data is stale and needs a refresh, therefore you should always have a way to reset the values of the cells, if you have a custom cell you should expose the controls you are using and set their values accordingly in cellForRowAtIndexPath, if you require to change a cell you should either change the data source values and reload the cell via - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation , or grab a hold of the cell with cellForRowAtIndexPath and change the values accordigly... my point is no need to recreate the cell..

Resources