Can you fast enumerate a NSIndexSet
? if not, what's the best way to enumerate the items in the set?
6 Answers
In OS X 10.6+ and iOS SDK 4.0+, you can use the -enumerateIndexesUsingBlock:
message:
NSIndexSet *idxSet = ...
[idxSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
//... do something with idx
// *stop = YES; to stop iteration early
}];

- 107,306
- 24
- 181
- 206
-
2Change NSInteger to NSUInteger – cocoafan Jul 19 '11 at 10:45
-
1This is the actual answer, can asker change? – Jameson Aug 20 '14 at 21:50
-
Worth noting that this is also available in iOS SDK 4.0+ – Jesse Feb 11 '15 at 20:08
A while loop should do the trick. It increments the index after you use the previous index.
/*int (as commented, unreliable across different platforms)*/
NSUInteger currentIndex = [someIndexSet firstIndex];
while (currentIndex != NSNotFound)
{
//use the currentIndex
//increment
currentIndex = [someIndexSet indexGreaterThanIndex: currentIndex];
}

- 54,662
- 15
- 117
- 144
-
2Valid indexes can exceed the range of values representable by `int`, since indexes are unsigned. Further, when targeting a 64-bit platform or building with `NS_BUILD_32_LIKE_64` defined, the index is a 64-bit value. Use `NSUInteger` instead of `int` in order to match the type stored by `NSIndexSet` under all platforms. – Jeremy W. Sherman Nov 17 '10 at 21:34
-
2@Jeremy W. Sherman: actually the indexes are effectively limited to those values that can be represented by a **positive** `NSInteger` because the "not found" return value is `NSNotFound` which is the same as `NSIntegerMax` – JeremyP Nov 19 '10 at 15:45
-
1@Evan: this example is still wrong. The comparison in the while loop needs to be against `NSNotFound` *not* -1. – JeremyP Nov 19 '10 at 15:46
-
@Evan: Interesting. I was using the Apple developer documentation as a reference. It seems a little experimentation is needed... http://developer.apple.com/library/mac/#DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSIndexSet_Class/Reference/Reference.html%23//apple_ref/occ/cl/NSIndexSet – JeremyP Nov 19 '10 at 15:55
-
@Evan Mulawski: Just verified that the Apple documentation is correct. `-indexGreaterThanIndex:` does return NSNotFound, not -1. The issue in the discussion occurs because he like you was using the wrong return type. – JeremyP Nov 19 '10 at 16:01
-
@JeremyP Wow, I never before noticed that using a signed `NSNotFound` halves the range of index values `NSUInteger` could represent if `NSNotFound` were instead `NSUIntegerMax`. I suppose `NSNotFound` is `NSIntegerMax` so as to agree with `kCFNotFound`; the `CFIndex` type used by CF collections is a signed long. @EveryoneElse Even with indices capped at `NSNotFound` (`NSIntegerMax`), `int` is still the wrong choice to store an index, because the range of `NSInteger` exceeds the range of `int` in 64-bit builds and builds with `NS_BUILD_32_LIKE_64` defined. – Jeremy W. Sherman Nov 19 '10 at 16:49
Fast enumeration must yield objects; since an NSIndexSet contains scalar numbers (NSUInteger
s), not objects, no, you cannot fast-enumerate an index set.
Hypothetically, it could box them up into NSNumbers, but then it wouldn't be very fast.

- 95,783
- 15
- 211
- 370
-
1I don't mind the performance hit, but you'd have to slow enumerate before you fast enumerate, right? – Dan Rosenstark Feb 03 '15 at 19:08
-
1With tagged pointers (on 64-bit platforms since OS X 10.7 and iOS 5), `NSIndexSet` fast enumeration ought to be pretty fast. – rob mayoff Jun 23 '16 at 03:44
Short answer: no. NSIndexSet
does not conform to the <NSFastEnumeration>
protocol.

- 242,470
- 58
- 448
- 498
-
what about enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {} --- is this not fast enumeration? – Motti Shneor Dec 12 '17 at 20:31
Supposing you have an NSTableView
instance (let's call it *tableView
), you can delete multiple selected rows from the datasource (uhm.. *myMutableArrayDataSource
), using:
[myMutableArrayDataSource removeObjectsAtIndexes:[tableView selectedRowIndexes]];
[tableView selectedRowIndexes]
returns an NSIndexSet
.
No need to start enumerating over the indexes in the NSIndexSet
yourself.

- 325
- 2
- 18
-
This isn't actually answering the question, but rather saying "maybe you didn't need to ask that question to start with. What do you want this fast enumeration for?" – Motti Shneor Dec 12 '17 at 20:27
These answers are no longer true for IndexSet in Swift 5. You can perfectly get something like:
let selectedRows:IndexSet = table.selectedRowIndexes
and then enumerate the indices like this:
for index in selectedRows {
// your code here.
}

- 3,744
- 1
- 22
- 43