views:

56

answers:

2

I am attempting to add a category to NSMutableArray to allow me to use it as a 2D array (backed by the 1D array, with a method to convert x & y indexes into a flat index). As I am not allowed to add instance variables to a category, how should I keep track of row and column counts which are required to calculate the index into the array?

Here is the interface:

@interface NSMutableArray (TK2DMutableArray)
- (id) initWithColumns:(int) columns rows:(int) rows;
- (id) objectAtColumn:(int) col row:(int) row;
- (void) putObject:(id) object atColumn:(int) x Row:(int) y;
@end

And here is the implementation:

@implementation TK2DMutableArray

- (id) initWithColumns:(int) x rows:(int) y {
    self = [self initWithCapacity:x * y];

    return self;
}

- (id) objectAtColumn:(int) col row:(int) row {
    return [self objectAtIndex:[self indexAtColumn:col row:row]];
}

- (void) putObject:(id) object atColumn:(int) x row:(int) y {
    [self replaceObjectAtIndex:[self indexAtColumn:x row:y] withObject:object];
}

- (int) indexAtColumn:(int) col row:(int) row {
    return (col + (row * rows));
}

@end

I originally coded it up as a subclass of NSMutableArray; I now know that was a mistake having read up a little on class clusters. The problem is right there in the last method - what should I do with rows? It'd be a regular old ivar if I was subclassing.

I'm fully expecting to be told to create a new class with an NSMutableArray as a property, but I wanted to see if there was a way to do it with categories first.

Many thanks.

+3  A: 

On 10.6 and later (I'm not sure about iOS), you can use objc_setAssociatedObject to associate arbitrary things to an object, see this Apple doc. You can use this mechanism to "add" and ivar.

But I think it's better for you to create a new class with an NSMutableArray as a property. That way, you can distinguish a 1d array and a 2d array at the level of the types, so that the compiler can warn you. For example, you don't want to accidentally use objectAtIndex: on a 2d array, right?

Yuji
OK thanks, worth a try. Associations might work but I agree with you: new class it is.
Tim Kemp
+2  A: 

If you really need a class that has the interface of NSMutableArray and your 2d array operations you probably should subclass NSMutableArray. Since this is a class cluster you also must implement the primitive operations of NSArray and NSMutableArray. These are count, objectAtIndex:, insertObject:atIndex:, removeObjectAtIndex:, addObject:, removeLastObject, and replaceObjectAtIndex:withObject: as well as any init-Methods you require. You then could implement the storage yourself or simply forward them to a NSMutableArray instance variable.

But you’re probably better off with a new class for your 2d arrays as Yuji suggested.

Sven
Thanks for the detailed reply Sven. It's way too much work for such a simple requirement. A new class with the backing array as an ivar will work fine, but it's nice to have the full list here should I need it for something else.
Tim Kemp