tableView.cellForRowAtIndexPath(indexPath) return nil
As stated in the documentation, cellForRowAtIndexPath
returns:
An object representing a cell of the table, or nil if the cell is not visible or indexPath is out of range.
Hence, unless your table is fully displayed, there are some off screen rows for which that method returns nil
.
The reason why it returns nil
for non visible cells is because they do not exist - the table reuses the same cells, to minimize memory usage - otherwise tables with a large number of rows would be impossible to manage.
tableView:indexPathForCell returns nil
It could be that the cell is not visible at this moment. tableView:indexPathForCell returns nil in this situation. I solved this using indexPathForRowAtPoint this method works even if the cell is not visible. The code:
UITableViewCell *cell = textField.superview.superview;
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:cell.center];
tableView.cellForRowAtIndexPath returns nil with too many cells (swift)
Because cells are reused, cellForRowAtIndexPath will give you cell only if cell for given indexPath is currently visible. It is indicated by the optional value. If you want to prevent from crash, you should use if let
if let cell = tableView?.cellForRowAtIndexPath(indexPath) as? MenuItemTableViewCell {
// Do something with cell
}
If you want to update values from cell, your cells should update the dataSource items. For example you can create delegate for that
protocol UITableViewCellUpdateDelegate {
func cellDidChangeValue(cell: UITableViewCell)
}
Add delegate to your cell and suppose we have a textField in this cell. We add target for the didCHangeTextFieldValue:
for EditingDidChange event so it is called every time the user types somethink in it. And when he do, we call the delegate function.
class MyCell: UITableViewCell {
@IBOutlet var textField: UITextField!
var delegate: UITableViewCellUpdateDelegate?
override func awakeFromNib() {
textField.addTarget(self, action: Selector("didCHangeTextFieldValue:"), forControlEvents: UIControlEvents.EditingChanged)
}
@IBAction func didCHangeTextFieldValue(sender: AnyObject?) {
self.delegate?.cellDidChangeValue(cell)
}
}
Then in cellForRowAtIndexPath
you add the delegate
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellIdentifier", forIndexPath: indexPath)
cell.delegate = self
return cell
}
And finally we implement the delegate method:
func cellDidChangeValue(cell: UITableViewCell) {
guard let indexPath = self.tableView.indexPathForCell(cell) else {
return
}
/// Update data source - we have cell and its indexPath
}
Hope it helps
indexPathForCell: returning nil
Assuming you are using storyboards and if you are willing to change the approach you are using a possible solution would be (And a cleaner solution in my opinion):
Drag an outlet of your UICollectionView
inside your cell into the UITableViewCell
. In your storyboard again set the delegate
and dataSource
of the UICollectionView
to your class by dragging the outlet. Of course you will have to use a custom UITableViewCell
In your cellForRowAtIndexPath
for the UITableView
set the tag of the the UICollectionView
to be your indexPath.row
. Now in your numberOfItemsInSection
you can access the UICollectionView
tag property and it will contain the indexPath.row
of the UITableViewCell
you are trying to access and hence you can access your model.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
// do stuff to setup the cell
// now reload the collection view that it contains
cell.collectionView.tag = indexPath.row;
[cell.collectionView reloadData];
return cell;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
// get my model from the index path and return the count of an array it contains
Model *model = dataArray[collectionView.tag];
return model.count;
}
Related Topics
Notification in Swift Returning Userinfo in Dictionary
How to Use @Fetchrequest Outside a View
Convert Single File to Swift 3 in Xcode 8
How to Draw a Line Between Two Points Over an Image in Swift 3
Swift - Measurement Convert(To:) Miles to Feet Gives Wrong Result
Cell Is Duplicated Multiple Times When Posting to Firebase
Difference When Declaring Swift Protocol Using Inheritance from Another Protocol or Using Where Self
Xcode - Upgrade to Swift 4 Manually
How to Disable The Automatic Activation of an Arcoachingoverlayview
How to Print Http Request to Console
Swift - How to Deal with Uncaught Exception
Is There Any Difference at All Between Suffix(From:) and Dropfirst(_:)
Preferredstatusbarupdateanimation Being Ignored
How to Fix Cannot Find 'Firebaseapp' in Scope