Jay Slupesky
Jay Slupesky

Reputation: 1913

Fast Enumeration on an NSArray category for NSIntegers

Since I use NSInteger arrays frequently, I wrote a category for NSArray (and one for NSMutableArray too) that adds methods such as integerAtIndex:, arrayByAddingInteger:, etc. The methods take care of wrapping/unwrapping the NSInteger in an NSNumber object.

What I'm wondering is whether there is a way I can enhance my category so that I can do fast enumeration on the NSIntegers. I would like to be able to write:

NSArray* arrayOfIntegers;
    .
    .
    .

for(NSInteger nextInteger in arrayOfIntegers)
    {
    }

….so that "nextInteger" is pulled out of the NSNumber object behind the scenes. Can I do this?

Upvotes: 7

Views: 455

Answers (3)

Tharabas
Tharabas

Reputation: 3422

I doubt that there is a clean way of doing this with NSFastEnumeration, as it heavily depends on the nextObject method.

But, you could do it in another way, by adding a block method for it:

@interface NSArray (Integers)
-(void)eachInteger:(void(^)(NSInteger))block;
@end

@implementation NSArray (Integers)
-(void)eachInteger:(void(^)(NSInteger))block {
  for (NSNumber *num in self) {
    block(num.integerValue);
  }
}
@end

That way, you could use it in your code in a similar way:

NSArray *arr = [NSArray arrayWithObjects:[NSNumber numberWithInt:23],
                                         [NSNumber numberWithInt:42],
                                         nil];
...
[arr eachInteger:^(NSInteger i) {
  NSLog(@"The int is %i", i);
}];
// =>
//    The int is 23
//    The int is 42

Perhaps you might want to take a look at the NSArray categories on the Lumumba Framework, which happens to be written by me :D

Upvotes: 4

Richard J. Ross III
Richard J. Ross III

Reputation: 55583

if you really like blocks, try this out:

@interface NSArray(blockIteration)

@property (copy, nonatomic, readonly) void (^forEachObject)(void (^block)(NSArray *, id));
@property (copy, nonatomic, readonly) void (^forEachInt)(void (^block)(NSArray *, int));
@property (copy, nonatomic, readonly) void (^forEachDouble)(void (^block)(NSArray *, double));

@end

@implementation NSArray(blockIteration)

-(void (^)(void (^)(NSArray *, id))) forEachObject
{
    return [^(void (^block)(NSArray *, id)) {
        block = [block copy];
        for (id obj in self)
        {
            block(self, obj);
        }
    } copy];
}

-(void (^)(void (^)(NSArray *, int))) forEachInt
{
    return [^(void (^block)(NSArray *, int)) {
        block = [block copy];
        for (NSNumber *num in self)
        {
            block(self, [num intValue]);
        }
    } copy];
}

-(void (^)(void (^)(NSArray *, double))) forEachDouble
{
    return [^(void (^block)(NSArray *, double)) {
        block = [block copy];
        for (NSNumber *num in self)
        {
            block(self, [num doubleValue]);
        }
    } copy];
}


@end

int main()
{
    NSArray *array = [NSArray arrayWithObjects:@"Hello", @"World", @"This", @"Is", @"A", @"Test", nil];

    array.forEachObject(^(id arr, id obj) {
        NSLog(@"%@", obj);
    });
}

Note that this implementation is ARC dependent.

Upvotes: 0

user529758
user529758

Reputation:

This exactly cannot be done, but you can easily convert your NSNumber into an NSInteger and use that later on. You can even write a macro for it:

#define int_enum(var, arr, block) \
    for(NSNumber *__tmp in arr) { NSInteger var = [__tmp integerValue]; block }

Use it like:

NSArray *array = // whatever;
int_enum(counter, array, {
    // things you want to do with `counter' as an NSInteger
});

Upvotes: 3

Related Questions