How can I loop through UITableView's cells?
IosUitableviewIos Problem Overview
I have n sections (known amount) and X rows in each section (unknown amount. Each row has a UITextField. When the user taps the "Done" button I want to iterate through each cell and do some conditional tests with the UITextField. If the tests pass data from each cell is written to a database. If not, then a UIAlert is shown. What is the best way to loop through the rows and if there is a more elegant solution to this please do advise.
Ios Solutions
Solution 1 - Ios
If you only want to iterate through the visible cells, then use
NSArray *cells = [tableView visibleCells];
If you want all cells of the table view, then use this:
NSMutableArray *cells = [[NSMutableArray alloc] init];
for (NSInteger j = 0; j < [tableView numberOfSections]; ++j)
{
for (NSInteger i = 0; i < [tableView numberOfRowsInSection:j]; ++i)
{
[cells addObject:[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
}
}
Now you can iterate through all cells:
(CustomTableViewCell is a class, which contains the property textField of the type UITextField)
for (CustomTableViewCell *cell in cells)
{
UITextField *textField = [cell textField];
NSLog(@"%@"; [textField text]);
}
Solution 2 - Ios
Here is a nice swift implementation that works for me.
func animateCells() {
for cell in tableView.visibleCells() as! [UITableViewCell] {
//do someting with the cell here.
}
}
Solution 3 - Ios
Accepted answer in swift for people who do not know ObjC (like me).
for section in 0 ..< sectionCount {
let rowCount = tableView.numberOfRowsInSection(section)
var list = [TableViewCell]()
for row in 0 ..< rowCount {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: row, inSection: section)) as! YourCell
list.append(cell)
}
}
Solution 4 - Ios
for xcode 9 use this - (similar to @2ank3th but the code is changed for swift 4):
let totalSection = tableView.numberOfSections
for section in 0..<totalSection
{
print("section \(section)")
let totalRows = tableView.numberOfRows(inSection: section)
for row in 0..<totalRows
{
print("row \(row)")
let cell = tableView.cellForRow(at: IndexPath(row: row, section: section))
if let label = cell?.viewWithTag(2) as? UILabel
{
label.text = "Section = \(section), Row = \(row)"
}
}
}
Solution 5 - Ios
for (UIView *view in TableView.subviews) {
for (tableviewCell *cell in view.subviews) {
//do
}
}
Solution 6 - Ios
Since iOS may recycle tableView cells which are off-screen, you have to handle tableView one cell at a time:
NSIndexPath *indexPath;
CustomTableViewCell *cell;
NSInteger sectionCount = [tableView numberOfSections];
for (NSInteger section = 0; section < sectionCount; section++) {
NSInteger rowCount = [tableView numberOfRowsInSection:section];
for (NSInteger row = 0; row < rowCount; row++) {
indexPath = [NSIndexPath indexPathForRow:row inSection:section];
cell = [tableView cellForRowAtIndexPath:indexPath];
NSLog(@"Section %@ row %@: %@", @(section), @(row), cell.textField.text);
}
}
You can collect an NSArray of all cells beforehands ONLY, when the whole list is visible. In such case, use [tableView visibleCells] to be safe.
Solution 7 - Ios
quick and dirty:
for (UIView *view in self.tableView.subviews){
for (id subview in view.subviews){
if ([subview isKindOfClass:[UITableViewCell class]]){
UITableViewCell *cell = subview;
// do something with your cell
}
}
}
Solution 8 - Ios
Here's a completely different way of thinking about looping through UITableView rows...here's an example of changing the text that might populate your UITextView by looping through your array, essentially meaning your tableView cell data.
All cells are populated with data from some kind of model. A very common model would be using an NSObject and NSMutableArray of those objects. If you were in didSelectRowAtIndexPath, you would then want to do something like this to affect the row you're selecting after modifying the array above:
for(YourObject *cellRow in yourArray)
{
if(![cellRow.someString isEqualToString:@""])
{
cellRow.someString = @"";
}
//...tons of options for conditions related to your data
}
YourObject *obj = [yourArray objectAtIndex:indexPath.row];
obj.someString = @"selected";
[yourArray insertObject:views atIndex:indexPath.row];
[yourArray removeObjectAtIndex:indexPath.row];
[yourTable reloadData];
This code would remove all the UITextField's text in every row except the one you selected, leaving the text "selected" in the tapped cell's UITextField as long as you're using obj.someString to populate the field's text in cellForRowAtIndexPath or willDisplayRowAtIndexPath using YourObject and yourArray.
This type of "looping" doesn't require any conditions of visible cells vs non visible cells. If you have multiple sections populated by an array of dictionaries, you could use the same logic by using a condition on a key value. Maybe you want to toggle a cells imageView, you could change the string representing the image name. Tons of options to loop through the data in your tableView without using any delegated UITableView properties.