iPad: Iterate over every cell in a UITableView?
-
6Meaningless question, really: Cells are pooled and reused. Generally, if you don't see it on a screen it doesn't exist. Elaborate please on what you're trying to do. – Steven Fisher Apr 13 '11 at 05:07
-
+1 to comment, why do you need to iterate over the cells? Usually you would iterate over the underlying data structure you populate the cells from. If you need to access the cells for some reason, then in `cellForRowAtIndexPath:` you can set a `cell` property of your underlying data structure to point to the initialised cell. Make sure it's an `@property (assign)` though, not a `retain`, since you don't want to keep all cells in memory for the sake of reuse. – Apr 13 '11 at 05:18
-
8It's not really meaningless; the UITableView exists as a visual representation of some backing datastore. And the datastore exists whether or not a particular subset of its data is currently on the screen. So iterating the cells is comparable to querying what is in the store, one row at a time. – aroth Apr 13 '11 at 05:19
-
It is meaningless. If you're querying the gui table then your architecture is wrong. You never need to scrub the table on the GUI, since all the data exists in the data store. The table is MVC and all of the data contained in the cell is in the data store based on that pattern. It's an issue of not understanding how MVC works. – Nick Turner Jan 22 '13 at 13:57
-
I agree with Nick Turner. Don't attempt what you describe (with possible exception that you have a small table, and have defined the cells as not being reusable). The recommended way to use tableviews is to maintain state in a separate *model*. *As user makes changes, you update that model with the changes*, by adding handler to each field's `editDidEnd` or similar method. Then when "Done", you are examining your custom model data - the displayed fields are not needed. – ToolmakerSteve Apr 07 '17 at 03:43
-
@aroth - Not exactly. The table view is a visual representation *of some subset of the backing store*. There is no guarantee that it is a complete representation. (well, you *can* make sure that all are generated during initialization, that cells are never reused, and hold on to them in your own custom array, as iOS asks for them. I've done that. I don't think I would do it again - its difficult to be certain that you haven't omitted some detail, and *create a problem that happens only under certain circumstances on certain devices*. How do you guarantee fully tested? I advise against it.) – ToolmakerSteve Apr 07 '17 at 03:52
-
There are valid reasons to do this. Example 1: Invalidate all NSTimers associated with visible cells before the table is removed (note that `tableView: didEndDisplayingCell:` does not get called on visible cells when a table disappears). Example 2: Perform some animation you want to happen in all cells in sync. – Agent Friday Jul 29 '22 at 21:40
7 Answers
for (int section = 0; section < [tableView numberOfSections]; section++) {
for (int row = 0; row < [tableView numberOfRowsInSection:section]; row++) {
NSIndexPath* cellPath = [NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:cellPath];
//do stuff with 'cell'
}
}

- 54,026
- 20
- 135
- 176
-
6It is normal that it only works on visible cells. Invisible cells are dequeued from the memory; cellForRowAtIndexPath will return nil for them. – Yunus Nedim Mehel Sep 24 '13 at 11:08
-
@RaviSharma add [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; and it will be used in non-visible cells. – zaolian Jan 25 '16 at 20:33
-
1@zaolian - think about what your suggestion does. Its a great example of why this whole approach is misguided: you are forcing the tableview to load every row from the source. If the needed info is in the source, then that is a better place to get it. If the question-asker was trying to read back *changes* from what is on screen, then your suggestion will seem to work - *until* user makes a change far enough down in a table, that scrolling back to the first row causes the changed row to be *discarded* - and lost forever - before this logic reads it. – ToolmakerSteve Apr 07 '17 at 04:02
To iterate over every visible cell in a UITableView:
for (UITableViewCell *cell in self.tableView.visibleCells) {
NSIndexPath *cellIndexPath = [self.tableView indexPathForCell:cell];
(edited to better state answer and hope that this is indexed more accurately for search results with the intention of saving others more time in the future)

- 6,100
- 3
- 32
- 36
-
3
-
I should've stated that - I updated my answer to reflect your comment. – AndrewPK Sep 13 '11 at 15:09
-
+1 for using an oop style instead of a function approach, even though you would'nt need to do this unless you're updating the GUI style. – Nick Turner Jan 22 '13 at 13:58
(This builds on aroths answer.)
I like to define this as a category to UITableView
so it's available everywhere.
(As mentioned a few times, you should be sure you really want to iterate over the cells themselves. For example: I use this to clear the UITableViewAccessoryCheckmark
's from all the cells before setting it to the user selected cell. A good rule of thumb is to do this only if the datasource methods can't do what you need to.)
Define like this:
- (void)enumerateCellsUsingBlock:(void (^)(UITableViewCell *cell))cellBlock {
NSParameterAssert(cellBlock != nil);
for (int section = 0; section < [self numberOfSections]; section++) {
for (int row = 0; row < [self numberOfRowsInSection:section]; row++) {
NSIndexPath *cellPath = [NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell *cell = [self cellForRowAtIndexPath:cellPath];
if (cellBlock != nil) {
cellBlock(cell);
}
}
}
}
Call like this:
[self.tableView enumerateCellsUsingBlock:^(UITableViewCell *cell) {
NSLog(@"cell:%@", cell);
}];
It would be good style to typedef the block, too.

- 9,227
- 10
- 65
- 96
Swift 4:
for section in 0...self.tableView.numberOfSections - 1 {
for row in 0...self.tableView.numberOfRows(inSection: section) - 1 {
let cell = self.tableView.cellForRow(at: NSIndexPath(row: row, section: section) as IndexPath)
print("Section: \(section) Row: \(row)")
}
}
by steve Iterate over all the UITableCells given a section id

- 1,434
- 17
- 16
Even simpler and more elegant:
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
// use the "cell" here
}
But obviously it doesn't fit all situations.

- 2,430
- 3
- 26
- 34
Assuming a variable myTableView
exists and its delegate and data source are both set:
UITableViewCell *cell;
NSIndexPath indexPath = [[NSIndexPath indexPathForRow:0 inSection:0];
for(indexPath.section = 0; indexPath.section < [myTableView numberOfSections]; ++indexPath.section)
{
for(indexPath.row = 0; indexPath.row < [myTableView numberOfRowsInSection:indexPath.section]; ++indexPath.row)
{
cell = [myTableView cellForRowAtIndexPath:indexPath];
// do something with this cell
}
}
-
Getting these errors for indexPath.row..... 1. Assignment to read only property 2. Increment to read only property.... – iSeeker Feb 21 '14 at 06:01
-
You mustn't have created a new `NSIndexPath` local variable. Check indexPath isn't the one being passed into your tableview data source function or something like that. – Feb 26 '14 at 01:03
This how Im iterating over all table view cells even not visible ones , check my answer here :
https://stackoverflow.com/a/32626614/2715840
Hint : code in Swift.
-
Your solution in OC version, just for reference: [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; – zaolian Jan 25 '16 at 20:33