2D arrays using NSMutableArray

后端 未结 8 795
夕颜
夕颜 2020-11-29 21:41

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

For example I have:

NSMutableArray *sections;
NSMutableArray *rows;
<
相关标签:
8条回答
  • 2020-11-29 22:06

    FYI: Jack's code needs a bunch of work before it works. Among other issues, the autorelease can cause the data to get released before you access it and his usage calls the class method arrayWithSections:rows: when it is actually defined as sectionArrayWithSections:rows:

    I may try to post actual working code later if I get a chance.

    0 讨论(0)
  • 2020-11-29 22:07

    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;
    
    0 讨论(0)
  • 2020-11-29 22:08

    what the hell. As long as we're reviving this question, here's something for the age of literal collection syntax and visual format interpretation!

    In case anyone is wondering, this works:

    NSMutableArray *multi = [@[ [@[] mutableCopy] , [@[] mutableCopy] ] mutableCopy];
    multi[1][0] = @"Hi ";
    multi[1][1] = @"There ";
    multi[0][0] = @"Oh ";
    multi[0][1] = @"James!";        
    NSLog(@"%@%@%@%@", multi[0][0], multi[1][0], multi[1][1], multi[0][1]);
    

    Result: "Oh Hi There James!"

    Of course, there is the problem of trying something like multi[3][5] = @"?" and getting an invalid index exception, so I wrote a category for NSMutableArray.

    @interface NSMutableArray (NullInit)
    +(NSMutableArray *)mutableNullArrayWithSize:(NSUInteger)size;
    +(NSMutableArray *)mutableNullArraysWithVisualFormat:(NSString *)string;
    @end
    
    @implementation NSMutableArray (NullInit)
    
    +(NSMutableArray *)mutableNullArrayWithSize:(NSUInteger)size
    {
        NSMutableArray *returnArray = [[NSMutableArray alloc] initWithCapacity:size];
        for (int i = 0; i < size; i++) {
            [returnArray addObject:[NSNull null]];
        }
        return returnArray;
    }
    
    +(NSMutableArray *)mutableNullArraysWithVisualFormat:(NSString *)string
    {
        NSMutableArray *returnArray = nil;
        NSRange bitRange;
        if ((bitRange = [string rangeOfString:@"^\\[\\d+]" options:NSRegularExpressionSearch]).location != NSNotFound) {
            NSUInteger size = [[string substringWithRange:NSMakeRange(1, bitRange.length - 2)] integerValue];
            if (string.length == bitRange.length) {
                returnArray = [self mutableNullArrayWithSize:size];
            } else {
                returnArray = [[NSMutableArray alloc] initWithCapacity:size];
                NSString *nextLevel = [string substringWithRange:NSMakeRange(bitRange.length, string.length - bitRange.length)];
                NSMutableArray *subArray;
                for (int i = 0; i < size; i++) {
                    subArray = [self mutableNullArraysWithVisualFormat:nextLevel];
                    if (subArray) {
                        [returnArray addObject:subArray];
                    } else {
                        return nil;
                    }
                }
            }
        } else {
            return nil;
        }
        return returnArray;
    }
    
    @end
    

    As you can see, we have a convenience method for making an array full of NSNull so that you can set indices with wild abandon.

    Secondly, there's a recursive method that parses a string with a visual format like: [3][12] (3 x 12 array). If your string is invalid in some way the method will return nil, but if it's valid you get a whole multidimensional array of the sizes you specify.

    Here are some examples:

    NSMutableArray *shrub = [NSMutableArray mutableNullArrayWithSize:5];
    NSMutableArray *tree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[3][12]"]; // 2-Dimensional Array
    NSMutableArray *threeDeeTree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[3][5][6]"]; // 3-Dimensional Array
    NSMutableArray *stuntedTree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[6][4][k]"]; // Returns nil
    

    You can pass as many dimensions as you like into the visual format method, and then access them with the literal syntax, like so:

    NSMutableArray *deepTree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[5][3][4][2][7]"];
    deepTree[3][2][1][0][5] = @"Leaf";
    NSLog(@"Look what's at 3.2.1.0.5: %@", deepTree[3][2][1][0][5]);
    

    Anyway, did this more as an exercise than anything else; it's probably pretty efficient in the grand scheme of things...considering as how we're making multi-dimensional arrays of Objective-C object pointers.

    0 讨论(0)
  • 2020-11-29 22:10

    Reviving an old thread, but I reworked Jack's code so 1. it compiles and 2. it is in the order of 2D c arrays [rows][columns] instead of [sections(columns)][rows] as he has it. Here you go!

    TwoDArray.h:

    #import <Foundation/Foundation.h>
    
    @interface TwoDArray : NSObject
    
    @property NSMutableArray *rows;
    
    - initWithRows:(NSUInteger)rows columns:(NSUInteger)columns;
    + sectionArrayWithRows:(NSUInteger)rows columns:(NSUInteger)columns;
    - objectInRow:(NSUInteger)row column:(NSUInteger)column;
    - (void)setObject:(id)obj inRow:(NSUInteger)row column:(NSUInteger)column;
    
    @end
    

    TwoDArray.m:

    #import "TwoDArray.h"
    
    @implementation TwoDArray
    
    - (id)initWithRows:(NSUInteger)rows columns:(NSUInteger)columns {
        if ((self = [self init])) {
            self.rows = [[NSMutableArray alloc] initWithCapacity: rows];
            for (int i = 0; i < rows; i++) {
                NSMutableArray *column = [NSMutableArray arrayWithCapacity:columns];
                for (int j = 0; j < columns; j++) {
                    [column setObject:[NSNull null] atIndexedSubscript:j];
                }
                [self.rows addObject:column];
            }
        }
        return self;
    }
    + (id)sectionArrayWithRows:(NSUInteger)rows columns:(NSUInteger)columns {
        return [[self alloc] initWithRows:rows columns:columns];
    }
    - (id)objectInRow:(NSUInteger)row column:(NSUInteger)column {
        return [[self.rows objectAtIndex:row] objectAtIndex:column];
    }
    - (void)setObject:(id)obj inRow:(NSUInteger)row column:(NSUInteger)column {
        [[self.rows objectAtIndex:row] replaceObjectAtIndex:column withObject:obj];
    }
    @end
    
    0 讨论(0)
  • 2020-11-29 22:12

    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];
    
    0 讨论(0)
  • 2020-11-29 22:15

    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.

    0 讨论(0)
提交回复
热议问题