I need to create a mutable two-dimensional array in Objective-C.

For example I have:

NSMutableArray *sections;
NSMutableArray *rows;

Each item in sections consists of an array rows. rows is an array that contains objects.

And I want to do something like this:

[ sections[i] addObject: objectToAdd]; //I want to add a new row

In order have something like this: section 0, rows: obj1, obj2, obj3 section 1, rows: obj4, obj5, obj6, obj 7...

Is there a way to do that in Objective-C?


First, you must allocate and initialize your objects before use, something like: NSMutableArray * sections = [[NSMutableArray alloc] initWithCapacity:10]; For the rows, you need one object for each, not a single NSMutableArray * rows;

Second, depending on whether you're using Xcode 4.4+ (which introduced subscripting, a.k.a section[i] & section[i] = …) you may have to use [sections objectAtIndex:i] for reading and [section replaceObjectAtIndex:i withObject: objectToAdd] for writing.

Third, an array cannot have holes, i.e., obj1, nil, obj2. You must provide actual object to every index. If you do need to put nothing, you can use NSNull object.

Moreover, don't forget that you can also store Objective-C objects in plain C arrays:

id table[lnum][rnum];
table[i][j] = myObj;

If you want to do this using arrays, you can intialize your sections array, then add a rows array as follows:

NSMutableArray *sections = [[NSMutableArray alloc] init];
NSMutableArray *rows = [[NSMutableArray alloc] init];
//Add row objects here

//Add your rows array to the sections array
[sections addObject:rows];

If you want to add this rows object at a certain index, use the following:

//Insert your rows array at index i
[sections insertObject:rows atIndex:i];

You can then modify this rows array by retrieving the array:

//Retrieve pointer to rows array at index i
NSMutableArray *rows = [sections objectAtIndex:i]
//modify rows array here

You could always create your own class called Section, which has an NSMutableArray member called rows; then you store your rows inside this array, and store the Section objects in an array:

@interface Section : NSObject {
    NSMutableArray *rows;
}

Then you simply create Section items, and you can create methods inside your class to add/remove row items. Then you package all the Sections items up inside another array:

Section *aSection = [[Section alloc] init];
//add any rows to your Section instance here

NSMutableArray *sections = [[NSMutableArray alloc] init];
[sections addObject:aSection];

This becomes more useful if you want to add more properties for each Section instance.


The language has no support for multi-dimensional object-oriented arrays, but you can make a class that does it using an NSMutableArray full of NSMutableArrays, like the following. I haven't tried compiling this or anything, I just typed it in.

@interface SectionArray : NSObject {
  NSMutableArray *sections;
}
- initWithSections:(NSUInteger)s rows:(NSUInteger)r;
+ sectionArrayWithSections:(NSUInteger)s rows:(NSUInteger)r;
- objectInSection:(NSUInteger)s row:(NSUInteger)r;
- (void)setObject:o inSection:(NSUInteger)s row:(NSUInteger)r;
@end
@implementation SectionArray
- initWithSections:(NSUInteger)s rows:(NSUInteger)r {
  if ((self = [self init])) {
    sections = [[NSMutableArray alloc] initWithCapacity:s];
    NSUInteger i;
    for (i=0; i<s; i++) {
      NSMutableArray *a = [NSMutableArray arrayWithCapacity:r];
      for (j=0; j<r; j++) {
        [a setObject:[NSNull null] atIndex:j];
      }
      [sections addObject:a];
    }
  }
  return self;
}
+ sectionArrayWithSections:(NSUInteger)s rows:(NSUInteger)r {
  return [[[self alloc] initWithSections:s rows:r] autorelease];
}
- objectInSection:(NSUInteger)s row:(NSUInteger)r {
  return [[sections objectAtIndex:s] objectAtIndex:r];
}
- (void)setObject:o inSection:(NSUInteger)s row:(NSUInteger)r {
  [[sections objectAtIndex:s] replaceObjectAtIndex:r withObject:0];
}
@end

You'd use it like this:

SectionArray *a = [SectionArray arrayWithSections:10 rows:5];
[a setObject:@"something" inSection:4 row:3];
id sameOldSomething = [s objectInSection:4 row:3];