Arrays 2D usando NSMutableArray

Necesito crear una matriz bidimensional mutable en Objective-C.

Por ejemplo, tengo:

NSMutableArray *sections; NSMutableArray *rows; 

Cada elemento en sections consta de una matriz de rows . rows es una matriz que contiene objetos.

Y quiero hacer algo como esto:

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

Para tener algo como esto: sección 0, filas: obj1, obj2, obj3 sección 1, filas: obj4, obj5, obj6, obj 7 …

¿Hay alguna manera de hacer eso en Objective-C?

En primer lugar, debe asignar e inicializar los objetos antes de su uso, algo así como: NSMutableArray * sections = [[NSMutableArray alloc] initWithCapacity:10]; Para las filas, necesita un objeto para cada una, no una sola NSMutableArray * rows;

En segundo lugar, dependiendo de si está usando Xcode 4.4+ (que introdujo la subscripción, también conocido como section[i] y section[i] = … ) puede que tenga que usar [sections objectAtIndex:i] para leer y [section replaceObjectAtIndex:i withObject: objectToAdd] para escribir.

En tercer lugar, una matriz no puede tener agujeros, es decir, obj1, nil, obj2. Debe proporcionar un objeto real a cada índice. Si no necesita poner nada, puede usar el objeto NSNull .

Además, no olvide que también puede almacenar objetos Objective-C en matrices simples en C:

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

Si desea hacer esto usando matrices, puede inicializar su matriz de sections y luego agregar una matriz de filas de la siguiente manera:

 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]; 

Si desea agregar este objeto de filas a un índice determinado, use lo siguiente:

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

A continuación, puede modificar esta matriz de filas recuperando la matriz:

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

Siempre puedes crear tu propia clase llamada Section , que tiene un miembro NSMutableArray llamado rows ; luego, almacena sus filas dentro de esta matriz y almacena los objetos de la Section en una matriz:

 @interface Section : NSObject { NSMutableArray *rows; } 

Luego, simplemente crea elementos de Section y puede crear métodos dentro de su clase para agregar / eliminar elementos de fila. Luego, empaqueta todos los elementos de las Sections dentro de otra matriz:

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

Esto se vuelve más útil si desea agregar más propiedades para cada instancia de Section .

El lenguaje no tiene soporte para matrices multidimensionales orientadas a objetos, pero puede crear una clase que lo haga usando un NSMutableArray lleno de NSMutableArrays, como el siguiente. No intenté comstackr esto ni nada, solo lo escribí.

 @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 

Lo usarías así:

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

que demonios. Mientras estemos reviviendo esta pregunta, aquí hay algo para la era de la syntax literal de la colección y la interpretación del formato visual.

En caso de que alguien se esté preguntando, esto funciona:

 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]); 

Resultado: “¡Hola, James!”

Por supuesto, existe el problema de intentar algo como multi[3][5] = @"?" y obtener una excepción de índice no válida, así que escribí una categoría para 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 

Como puede ver, tenemos un método de conveniencia para hacer una matriz llena de NSNull para que pueda establecer índices con salvaje abandono.

En segundo lugar, hay un método recursivo que analiza una cadena con un formato visual como: [3][12] (matriz de 3 x 12). Si su cadena no es válida de alguna manera, el método devolverá nil , pero si es válida obtendrá una matriz multidimensional completa de los tamaños que especifique.

Aquí hay unos ejemplos:

 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 

Puede pasar tantas dimensiones como quiera en el método de formato visual, y luego acceder a ellas con la syntax literal, así:

 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]); 

De todos modos, hizo esto más como un ejercicio que otra cosa; probablemente sea bastante eficiente en el gran esquema de cosas ... considerando cómo estamos haciendo arreglos multidimensionales de punteros de objeto Objective-C.

Gracias a Jack por su código, trabajé un poco; Necesito un conjunto de matrices multidimensionales para cadenas en uno de mis proyectos, todavía tiene algunas cosas que necesitan ser reparadas, pero solo funciona por el momento, lo publicaré aquí, estoy abierto a sugerencias, por favor, porque soy solo un principiante. en el objective c en este momento …

 @interface SectionArray : NSObject { NSMutableArray *sections; } - initWithSections:(NSUInteger)intSections:(NSUInteger)intRow; + sectionArrayWithSections:(NSUInteger)intSections:(NSUInteger)intRows; - objectInSection:(NSUInteger)intSection:(NSUInteger)intRow; - (void)setObject:(NSString *)object:(NSUInteger)intSection:(NSUInteger)intRow; @end @implementation SectionArray - initWithSections:(NSUInteger)intSections:(NSUInteger)intRow { NSUInteger i; NSUInteger j; if ((self = [self init])) { sections = [[NSMutableArray alloc] initWithCapacity:intSections]; for (i=0; i < intSections; i++) { NSMutableArray *a = [NSMutableArray arrayWithCapacity:intRow]; for (j=0; j < intRow; j++) { [a insertObject:[NSNull null] atIndex:j]; } [sections addObject:a]; } } return self; } - (void)setObject:(NSString *)object:(NSUInteger)intSection:(NSUInteger)intRow { [[sections objectAtIndex:intSection] replaceObjectAtIndex:intRow withObject:object]; } - objectInSection:(NSUInteger)intSection:(NSUInteger)intRow { return [[sections objectAtIndex:intSection] objectAtIndex:intRow]; } + sectionArrayWithSections:(NSUInteger)intSections:(NSUInteger)intRows { return [[self alloc] initWithSections:intSections:intRows] ; } @end 

Esto está funcionando bien!

Actualmente lo estoy usando así

 SectionArray *secA = [[SectionArray alloc] initWithSections:2:2]; [secA setObject:@"Object":0:0]; [secA setObject:@"ObjectTwo":0:1]; [secA setObject:@"ObjectThree":1:0]; [secA setObject:@"ObjectFour":1:1]; NSString *str = [secA objectInSection:1:1]; NSLog(@" object is = %@" , str); 

Gracias de nuevo Jack!

FYI: El código de Jack necesita mucho trabajo antes de que funcione. Entre otros problemas, la liberación automática puede hacer que los datos se liberen antes de acceder y su uso llama al método de clase arrayWithSections: rows: cuando en realidad se define como sectionArrayWithSections: rows:

Puedo intentar publicar el código de trabajo actual más tarde si tengo la oportunidad.

Reanimando un hilo viejo, pero rehice el código de Jack para que 1. se compile y 2. esté en el orden de 2D c matrices [filas] [columnas] en lugar de [secciones (columnas)] [filas] como lo tiene. ¡Aqui tienes!

TwoDArray.h:

 #import  @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 

Esto es lo que hice para inicializar una matriz de matrices.

 NSMutableArray *arrayOfArrays = [[NSMutableArray alloc] initWithCapacity:CONST]; for (int i=0; i<=CONST; i++) { [arrayOfArrays addObject:[NSMutableArray array]]; } 

Luego, más adelante en un código, pude simplemente:

 [[arrayOfArrays objectAtIndex:0] addObject:myObject];