Not getting all UITableViewCell from UITableView - ios

I have a custom cell within my UITableView with a textField in it. I'm trying to read the textFields' values from table view.
To get the cells and values from textFields, I'm using the below code:
for var i = 0; i < myTableView.numberOfRowsInSection(0); i++ { //5 records
let index: NSIndexPath = NSIndexPath(forRow: i, inSection: 0)
//getting the cell at position i
let cell = self.myTableView.cellForRowAtIndexPath(index) as! myCustomCell
//Read data
let newValue = cell.myTextField.text
}
I'm not getting any compiler errors, but when I run the application, it sometimes fails at cell index 0, sometimes at cell index 3, it is at a random position. The error I'm getting is:
fatal error: unexpectedly found nil while unwrapping an Optional value
Which I understand because the cell is not present within myTableView.
Can anyone point me in the right direction to be able to read all the custom cells from my table view?

UITableViewCells are getting recycled. That's why its not safe to do it your way. You need to use a Data Model as others already pointed out.

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.

UITableView.visibleCells() is not returning all cells

I am using a UITableViewController. The UITableView is presenting 11 custom Cells.
10 of those are dynamic, one is static.
Nevertheless counting the rows either with:
let cells = self.tableView.visibleCells as? [chatUebersicht]
or
for (var row = 0; row < gruppenNamen.count; row++) {
if let cell:chatUebersichtCell = table.cellForRowAtIndexPath(NSIndexPath(forRow: row, inSection: 0)) as? chatUebersichtCell {
cells.append(cell)
}
}
is returning the correct number. It is returning the number 5 each time.
I think there is an issue with preloading the cells. is there a way to overcome this?
visibleCells only returns the reusable cells you can currently see. That's the beauty of a UITableView - There isn't an instance of a cell for every row of data.
You should reevaluate what you are trying to do and determine whether it's a presentational operation or something that can be done by working with your array of data that feeds the tableview's data source.

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

Hide view in specific CollectionViewCell

I have question how to implement this stuff in right way.
So far I done
if indexPath.row == 1 {
let indexPatha = NSIndexPath(forRow: 0, inSection: 0)
let changeCell = collectionView .cellForItemAtIndexPath(indexPatha) as! BarCollectionViewCell
changeCell.addNewBottleSecondButton.alpha = 0
}
But when I swipe until cell is hidden, I am getting error, unexpectedly found nil while unwrapping an Optional value, and still this doesn't looks like how I want to make it.
I want to achieve that when I have more then one cell, I want to hide one specific view.
Would it work in your flow to handle this in cellForRowAtIndexPath instead?
After your initialize your cell:
cell.addNewBottleSecondButton.hidden = (indexPath.row == 0) && (dataItems.count > 1)
If the cell has been scrolled off the screen it may not exist anymore due to Apple's dequeue/re-use optimizations. Previously when confronted with this problem, I've had to set a state variable and handle the UI change in cellForRow if the cell didn't exist when trying to change the cell's UI.

Pass table cells textlabel data to array in swift

I want to pass table cell's textLabel data of UITableViewController to NSArray. Those cell have identifier name Cells and accessory type checkmark
Code that does exactly what you asked is here:
func getCellsData() -> [String] {
var dataArray: [String] = []
for section in 0 ..< self.tableView.numberOfSections() {
for row in 0 ..< self.tableView.numberOfRowsInSection(section) {
let indexPath = NSIndexPath(forRow: row, inSection: section)
let cell = self.tableView.cellForRowAtIndexPath(indexPath)!
if cell.reuseIdentifier == "Cells" && cell.accessoryType == UITableViewCellAccessoryType.Checkmark {
dataArray.append(cell.textLabel!.text!)
}
}
}
return dataArray
}
But I would like to recommend you find different approach, because this is the rude traverse of tableView. You probably have your dataSource model that can give you ll data you need. Additionally, this code doesn't check for errors, for example if there is no text in cell at some indexPath
Two things I'd advise.
First, looks like you're using the checkmark accessory to indicate multiple selections. It's really intended for single selection, like a radio button. Better to use the allowMultipleSelectionsoption on the tableview. This will allow...
...the second thing. Copying text from cells into an array is the wrong way round to do it. Better to ask the table view and call it's - (NSArray *)indexPathsForSelectedRows this will give you an array of index paths to selected cells then you can ask for each cell and grab any data you want from it. This gives you better live data and prevents you unknowingly creating a circular reference from the view controller of the tableview and the content in the tableview cells.

Resources