Cocoa and Objective-C: Up and Running (by me) is now available from O'Reilly.

Using NSIndexSet with NSArray

It turns out that there's no built-in way for NSArray to return a subarray using an NSIndexSet. Nor is there an indexEnumerator built into NSIndexSet. So here's a solution in the form of a category:

@interface NSArray (IndexSetAddition)
- (NSArray *)subarrayWithIndexes: (NSIndexSet *)indexes
@end

@implementation NSArray (IndexSetAddition)

- (NSArray *) subarrayWithIndexes: (NSIndexSet *)indexes
{
    NSMutableArray *targetArray  = [NSMutableArray array];
    unsigned count = [self count];

    unsigned index = [indexes firstIndex];
    while ( index != NSNotFound )
    {
        if ( index < count )
            [targetArray addObject: [self objectAtIndex: index]];
            
        index = [indexes indexGreaterThanIndex: index];
    }

    return targetArray;
}

@end
Design Element
Using NSIndexSet with NSArray
Posted Dec 17, 2004 — 5 comments below




 

kk — Mar 23, 06 952

Yeah, NSIndexSet is one of the duller knives in the Foundation drawer. Who spec'd _that_ gomer? Obviously someone who forgot the dictum about keeping simple things... simple.

I like your solution, although I would like to see an actual IndexEnumerator class.

I do suggest that if your method declares an NSArray as its return value, that you ought to actually return one. Apple's advice on return types is that you should assume that they are correct, even though they might not be. (?!?)

I feel that it is worth the miniscule cost to rigorously honor the declaration -- it minimizes the odds of a subtle bug down the road.

So,my only adjustment will be to change the return to:

return [[targetArray copy] autorelease];

Dan — Oct 26, 07 4846

I guess I'm a little late to the party, but as of 10.4, NSArray has an objectsAtIndexes: method that does just what you describe in this post.


So,my only adjustment will be to change the return to:

return [[targetArray copy] autorelease];


Just out of curiosity, would this approach have any advantages over using:

return [NSArray arrayWithArray:targetArray];

The latter seems to not involve copying the objects in the array, so it might be a little faster.

Scott Stevenson — Oct 26, 07 4849 Scotty the Leopard

@Dan: The latter seems to not involve copying the objects in the array, so it might be a little faster.

I don't think -copy does a "deep copy" for NSArray. If it did, it would cause big problems for array of objects which don't implement the NSCopying protocol.

It's possible foundation value objects (numbers, strings, etc) are special-cased, but my guess is that they're not.

Charlie — Jan 10, 08 5338

to KK: As admitted by Apple's staff (during their Dev Tour through Europe) the NSEnumarator classes are awful slow and inefficient as they actually copy all items of (e.g.) an array instead of just retaining it. Either use a for-i cycle or now in Leopard the for-in cycle which is faster than the for-i cycle (that's what folks at the Dev Tour said).

Ian Wilkinson — Mar 26, 09 6674

I do suggest that if your method declares an NSArray as its return value, that you ought to actually return one. Apple's advice on return types is that you should assume that they are correct, even though they might not be. (?!?)

I don't follow this at all. How would the NSMutableArray return type be deemed 'not correct' ? Doesn't basic inheritance and plymorphism dictate that we can return any subclass of NSArray that we please from the method?

I'm interested in seeing a link to the Apple advice that you are referring to.




 

Comments Temporarily Disabled

I had to temporarily disable comments due to spam. I'll re-enable them soon.




Technorati Profile
Copyright © Scott Stevenson 2004-2008