UItextfield text in Custom UITableViewCell prints nil when i scroll up in SE - ios

I am having a form made by using the UITableView . It is made by using the custom UITextField in the custom table view cell. But when i scroll up the top most cell of the UITableView cell prints nil. And when i try to print the data in the console it prints nil. MoreOver the text in the uitextfield in the custom cell also becomes nil. The code for getting the first cell of the UITableView cell is:
let username = self.profileManagement!.cellForRow(at: IndexPath(row: 0, section: 0)) as? RegistrationFieldTableViewCell!
But when i try to print the username in console using po username it returns nil.
Why it is happening ? Any ideas how to resolve it?

I am not sure if this is the best possible answer to this question, but having faced similar issues in the past the solution that worked for me was.
Store the values in a dictionary as an when the value is entered in the adjoining textField of the cell. You can achieve this by storing the value in the dictionary or an array in the method textFieldDidEndEditing and then setting it to the appropriate textField each time the cell reloads.

Related

Why does referencing an item that exists in a collection view return a nil value?

let x = X(name: "x")
blocks.append(newBlock)
let indexPath = IndexPath(row: blocks.count - 1, section: 0)
collectionView.insertItems(at: [indexPath])
let aCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell
The above code is in a function that runs when a button is pressed in the view controller to present a new item in the collection view. As collectionView.insertItems(at: [indexPath])adds a new item at the specific index, I don't understand why let aCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCellwould return a nil value. The specific error is "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value". I only get this error when the cell is outside of the screen. Meaning that if I add an item when there are few cells on the screen or if I scroll to the bottom if there are many cells and add a new item, it'll work. However, If there are many items and I do not scroll down, it'll have that error
The documentation for cellForItem(at:) says this:
this method returns nil if the cell isn't visible or if indexPath is out of range
You're getting a nil value because your cell is outside of the screen, and the force-cast is causing a crash. You should avoid force-casting in general.
Update
I think you might be unfamiliar with the way tables and collection views work. They don't store a cell for every row/item that you have, instead they create a pool of cells and reuse them.
When the cell goes out of bounds, the table/collection view stops associating it with the IndexPath and, as the user scrolls, this old cell is used again for the new IndexPath that needs to be displayed.
In general, you should configure your cell completely in collectionView(_:cellForItemAt:), and only use cellForItem(at:) to update a visible cell when the content that should be displayed on it changes.
There are 2 similar methods. UICollectionView implements the method cellForItem(at:) and the UICollectionViewDataSource protocol defines the method collectionView(_:cellForItemAt:) They do different things.
The UICollectionView method cellForItem(at:) will return a cell at the specified IndexPath if it is on screen and not out of range. It's meant for fetching cells that are currently visible.
If you call that method when the first 5 cells of your single-section collection view are visible, and ask for the indexPath of the 6th cell, you will get a nil back. That is what's happening in your code. You're trying for force cast nil to CollectionViewCell, so your code crashes. Don't do that. Check to see if you get back a nil, and handle nil gracefully.
If you scroll down so that cell 6 is visible and then ask for cell 6, it will be returned. If it's currently off-screen, it will return nil. As #EmilioPelaez says in his answer (voted), that's how the function works.
The other method collectionView(_:cellForItemAt:) is the method the collection view calls to ask its data source to create and configure cells. That method must always return a cell for any valid IndexPath in your model. You should't call that method directly though.

fatal error: unexpectedly found nil while unwrapping an Optional value in Tableview

I had implemented UITableView with custom cell.It works fine.
Tableviewcell have 3 textfields in every cell.
I try to access all cell on submit button.
But app is crash due to access non-visible cell.
How can I got all cell's all 3 textfield values even they are not visible.
Thank you,
UITableView's cellForRowAtIndexPath method will return nil if cell not visible. You should check for this, and perform only data source changes if so:
if let cell_note = self.tbl.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 4)) as? NotesCell
{
// do something with your data source
// do something with cell_note that already loaded on screen
}
else
{
// do something with your data source
// your cell didn't loaded yet
// you should only prepare fresh information in your data source for delegate method tableView(_:cellForRowAtIndexPath:)
}
Note that if you have same data source changes for both cases (as usual in fact), you need move them out of this check

if the custom tableviewCell has "TextField", how it easy to map to modal property?

Situation:
if there has a UITableview have 10 cell on it,
there have "UILabel + UITextField" in each cell, also have 10 modal property corresponding to each cell, Each cell is get value in different property in the modal, also user change the value in the UITextField on the cell, also update the corresponding modal properTY value
like :
value in modal.name is corresponding "section:1 row:1" cell
value in modal.age is corresponding "section:1 row:2" cell
....
question:
is there have any easy way handle this situation?
cause i dont't like to set the value one by one in method "cellForRowAtIndexPath"
like:
if (indexPath.section == 1 && indexPath.row == 1) {
cell.textFiled = modal.name;
}
also the textField value change in cell"section:1 row:1", how to update the "modal.name" easily?
Thanks
You can add two methods in custom cell class.
One is: -(void)configureCellWithModel for display data.
Another is: -(void)updateCellWothModel for update data.
Put these methods in the custom cell class.

UITableView changing things of some cells in Swift

I have a UITableView with a custom UITalbeCellView. Every cell has a title a body and a date. When I fetch the data some of the titles must be red so there is a Bool that is set to true for those cells which title has to be red.
The first time the data is fetched it looks fine, but as you scroll up and down a few times all of the titles end up being red.
Im using an array of structures to store the data and on the cellForRowAtIndexPath there is an if and if the boolean in that position of the array is true I change the color to red:
let cell = tableView.dequeueReusableCellWithIdentifier("CommentsRowTVC", forIndexPath: indexPath) as! CommentsRowTVC
let single_comment = self.AOS[indexPath.row]
cell.titulo_comentario?.text = single_comment.titulo_comment
if single_comment.flag == true {
cell.titulo_comentario.textColor = UIColor.redColor()
}
Im gessing it reuses Views or something like that. Does this have any easy fix? Or do I have to implement my own TableView to prevent this from happening?
Im also thinking the method dequeueReusableCellWithIdentifier might be the one causing my problem... but Im new on swift and cant think of any replacement for that.
It is happening similar thing on buttons there are on the cells, when you click a button from a cell it changes its color and disables it, but just the one on that cell. However when clicking on a cell, buttons from other cells are also suffering those changes.
Since cells get reused you end up with cells that were previously red because they hadsingle_comment.flag == true and are now used for another row where there actually is single_comment.flag == false. You have to reset the color in the else branch again:
if single_comment.flag == true {
cell.titulo_comentario.textColor = UIColor.redColor()
} else {
cell.titulo_comentario.textColor = UIColor.whiteColor()
}
UITableViews reuse their cells, meaning that you will get cells inside your cellForRowAtIndexPath which have previously been used before, maybe have have set the textColor to red. Your job is it now to revert the color of the text to its original state.
In general whatever change you make inside the if-branch of cell-customization has to be undone in the else-branch. If you remove a label in the if, add it in the else.

Swift 2.0, UITableView: cellForRowAtIndexPath returning nil for non-visible cells

Please don't mark this as a duplicate question because I have found no suitable answer for my query.
I have a table view with cells that contain text fields. I have a button at the bottom of the screen. The number of rows is greater than the screen can display, so some cells are not in view. I want that at any point when the button is pressed, all textfields be read and the text input be processed. I am unable to do so because apparently because of the reusability of cells, cells out of view do not exist at all and cellForRowAtIndexPath for those indexPaths gives a runtime error. I have read answers that say that this simply can't be done. But I find it hard to believe that there is no workaround to this. Please help. Thanks in advance!
This definitely can't shouldn't be done (accessing cells that are off screen, or implementing workarounds to allow it), for reasons of (at least) performance and memory usage.
Having said that there is, as you put it, a workaround. What you will need to do it change how you are storing the values in those text fields. Rather than iterating through cells and retrieving the text directly from the text fields you should store the text for each field in an collection.
Define a dictionary property on your table view controller / data source to hold the text for each row.
Act as the delegate of UITextField and assign as such in tableView:cellForRowAtIndexPath:
Implement textField:didEndEditing: (or whatever is appropriate for your use case) and store the text in the dictionary keyed against the index path relating to the cell that contains that text field.
Update the button action method to use this dictionary instead of iterating through cells.
Create a UITableViewCell subclass, add your tableViewCells a index property and introduce a delegate like:
protocol CustomCellDelegate {
func didEditTextField(test : String, atIndex : Int)
}
Create a delegate variable on your UITableViewCell subclass.
var delegate : CustomCellDelegate?
Implement the UITextViewDelegate in your tableViewCell and set the cell to be the delegate of your textfield.
Implement these two methods:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(textField : UITextField) {
// call back with the delegate here
// delegate?.didEditTextField(textfield.text, atIndex: self.index)
}
So when the user ends editing the textField, your cell will call out with a delegate, sending the text and the index.
On your viewController, when you init your tableViewCell, set the delegate of the cell to the viewController, and set the index to indexPath.row .
Set up on your viewController a String array with as many items as many tableViewCells you got. Init the array with empty strings.
So you got the delegate on your viewController, and whenever it is called, you just insert the returned text to right index in the string array on your viewcontroller.
What do think, will this work?
If we can assume that cells that have NEVER been created has no text inputs, then create an Array or Set ourselves and clone the content/input texts there whenever user inputs to a cell's textfield.
Whenever, that button is clicked, you can iterate the array instead of cells to get all the inputs.
This is a bit hacky though..

Resources