gm_
gm_

Reputation: 617

Int vs. IndexPath Troubles

I am writing a function to loop through all of the cells in a UITableViewController. Here is what I have so far:

var i = 0
while (i < tableView.numberOfRows(inSection: 0)) {
    i += 1
    let cell = tableView.cellForRow(at: i-1)
}

Everything loops correctly until I try to get the cell. It expects an input of type IndexPath, however I am passing in an Int. Whenever I force it as an IndexPath like so:

let cell = tableView.cellForRow(at: i-1 as! IndexPath)

I get a warning saying that it will always fail/ always return nil. Is there a better way to do this, or am I just missing a crucial step. Any help is greatly appreciated. Thanks in advance!

EDIT (A LITTLE MORE EXPLANATION): All the cells are custom classed cells, with a specific variable. I want to loop through all of the cells and get that value.

let visibleCells = tableView.visibleCells
for aCell in visibleCells {
    print(aCell.question?.text) <------- this is the value I want
}

Upvotes: 0

Views: 111

Answers (4)

Fahim
Fahim

Reputation: 3556

You should create an IndexPath via code, like this:

let ndx = IndexPath(row:i, section: 0)

Or, to modify your code:

var i = 0
while (i < tableView.numberOfRows(inSection: 0)) {
    i += 1
    let ndx = IndexPath(row:i-1, section: 0)
    let cell = tableView.cellForRow(at:ndx)
}

Based on the later edit where you mention that you want the value of a text string on each row, I would suggest that the above is probably not the best way to approach this :) (I know others have already said this, but I didn't want to make assumptions about what you wanted to do unless you specifically stated what you wanted ...)

You are probably better off taking the same approach you take to populate the data for the table view cells via cellForRowAt: to get the question text than to loop through all the table rows, which would result in some issues for non-visible rows as others have indicated already.

If you have any issues with getting the data provided for cellForRowAt:, do share the code for the cellForRowAt: with us and I'm sure one of us can help you figure things out :)

Upvotes: 2

gm_
gm_

Reputation: 617

I believe I have figured it out using all of the help from you wonderful people.

In my case, I have a custom class with a variable that I want access to. I can do what Taylor M, Fahim, and Duncan C said: let indexPath = IndexPath(row: i, section: 0)

Then I can add as! NumberTableViewCell to the end, which allows me access to the values defined there. In the end, it looked like this:

var i = 0
while (i < tableView.numberOfRows(inSection: 0)) {
    i += 1
    var cell = tableView.cellForRow(at: IndexPath(row: i-1, section: 0)) as! NumberTableViewCell
    print(cell.question.text!)
    }

Thank you all for your help!

Upvotes: 0

Duncan C
Duncan C

Reputation: 131398

Most of the information below has been said by others in the other answers and comments, but I wanted to put it all in one place:

We need to step back from the specifics of the question and ask what you are actually trying to do.

The UITableView method cellForRow(at:) will only return cells that are actually on-screen. If there is only room for 5 cells and you have to scroll to expose the rest, that method will return nil for all but the cells that are visible.

As others have suggested, if your goal is to loop through the cells that are on-screen the property tableView.visibleCells would be a better choice.

If your goal is to loop through all cells that exist in your data then you need to explain what you are trying to do.

As for your specific question, the cellForRow(at:) wants a parameter of type IndexPath. You can't simply cast an Int to IndexPath. That will fail. Instead, as @TaylorM said in their answer, you need to create an IndexPath. If your table view only has a single section then you can simply use

let indexPath = IndexPath(row: i, section: 0)

(Assuming you fix your loop code so your indexes start at 0.)

It also does not make sense to use a while loop like that.

Instead of all of this, I suggest using:

let visibleCells = tableView.visibleCells
for aCell in visibleCells {
   //Do something with the cell
}

Upvotes: 2

Taylor M
Taylor M

Reputation: 1865

Try

let indexPath = IndexPath(row: i, section: 0)

You may need to adjust the section to fit your needs.

Check out the documentation for IndexPath. Like most classes and structures, IndexPath has initializers. If you need to create a new instance of any object, you'll most like use an initializer.

*also see the comment from @rmaddy: "Unrelated to your question but I can almost guarantee that your attempt to loop through all of the cells is the wrong thing to do. What is your actual goal with that loop?"

Upvotes: 0

Related Questions