views:

577

answers:

2

Is there a better way than what is proposed here to create a one-to-one mapping between an table view cell's NSIndexPath and a unique NSUInteger or int, in order to create a unique tag property value for a widget in the cell (a UIProgressView)?

The link adds methods through a UIKit category extension that converts between NSIndexPath and int, but they only work for less than a certain number of rows.

Granted, I may not run into that limit, but I'm wondering if there is a mapping that someone has come up with that can be guaranteed to work for any number of rows.

+1  A: 

No, there really isn't a way that is guaranteed to work for any number of rows. If you have a table with 2 sections, each with 3 billion rows, then there's no way to map those 6 billion potential NSIndexPaths into the 4 billion 32-bit NSIntegers.

(if you were building a 64-bit app, the same thing is true, but the numbers would have to be another 4 billion times bigger in the example.)

They use a limit of 10,000 rows per section in the example you linked to; if you're seriously worried you might have more rows than that, you could use a bigger constant, i.e. you could use 1,000,000 as the maximum number of rows if you know you won't have more than 4,000 sections.

Note that a "real programmer" would presumably use 65536 as the constant, of course.

David Maymudes
I know I can use a bigger constant. Just wondering if there is a generic way to do this without having to play with constants. Perhaps I should file a feature request to Apple...
Alex Reynolds
No, there just logically can't be a way to map any possible NSIndexPath to an NSInteger, because an NSIndexPath has *two* NSIntegers in it. You just can't put 64 bits of possible information into a 32-bit box, unless you assume that the row/section are small enough to put into a 16-bit field.
David Maymudes
A: 

If I had a need to do this I would simply shift the section path to one half of a 32-bit int, and shift the row part to the other. Yes this means you can't have more than 65535 elements in a row (in breaking it out I assumed unsigned ints since row/section will never be negative) but I'll take an assumed limit far larger than I will ever need, over a magic constant any day.

Plus it's cheaper computationally.

Usually in this situation though I set up my table view controller as a delegate for each cell, and the cell can call back the controller with any changes along with some key value used to create the cell - after all when you are populating a cell you know how to reach into your data set to pull out values. Heck, you could even simply store the IndexPath into the cell and it can call back with that. The reason I would not use the IndexPath approach or the prior one involving flattening NSIndexPath into a tag is that if you ever start changing rows dynamically the values could become unaligned between the NSndexPath you created a cell with and the value for the current dataset. Much better to have some kind of key that will always get you back to the right data logically.

Kendall Helmstetter Gelner
"Much better to have some kind of key that will always get you back to the right data logically." Unfortunately, Apple only seems to provide the tag value to get back to a widget, so I need some way to translate a fetched results controller item to a tag value, so that I can update a cell's progress view.
Alex Reynolds
Why do you not use cellForRowAtIndexPath: to get the cell you need, and tell it to update its progress bar? Tags can be useful as a shortcut but they are never the only path.
Kendall Helmstetter Gelner