Matrizes 2D usando NSMutableArray

Eu preciso criar uma matriz bidimensional mutável em Objective-C.

Por exemplo eu tenho:

NSMutableArray *sections; NSMutableArray *rows; 

Cada item nas sections consiste em uma rows matriz. rows é uma matriz que contém objects.

E eu quero fazer algo assim:

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

Para ter algo assim: seção 0, linhas: obj1, obj2, obj3 seção 1, linhas: obj4, obj5, obj6, obj 7 …

Existe uma maneira de fazer isso em Objective-C?

Primeiro, você deve alocar e inicializar seus objects antes de usar, algo como: NSMutableArray * sections = [[NSMutableArray alloc] initWithCapacity:10]; Para as linhas, você precisa de um object para cada, não um único NSMutableArray * rows;

Segundo, dependendo se você está usando o Xcode 4.4+ (que introduziu o subscripting, também conhecido como section[i] & section[i] = … ) você pode ter que usar [sections objectAtIndex:i] para leitura e [section replaceObjectAtIndex:i withObject: objectToAdd] para escrever.

Em terceiro lugar, um array não pode ter buracos, ou seja, obj1, nil, obj2. Você deve fornecer o object real para cada índice. Se você precisar colocar nada, você pode usar o object NSNull .

Além disso, não esqueça que você também pode armazenar objects Objective-C em matrizes C simples:

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

Se você quiser fazer isso usando matrizes, você pode inicializar sua matriz de sections , em seguida, adicionar uma matriz de linhas da seguinte maneira:

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

Se você deseja adicionar esse object de linhas em um determinado índice, use o seguinte:

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

Você pode modificar essa matriz de linhas recuperando a matriz:

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

Você sempre pode criar sua própria class chamada Section , que possui um membro NSMutableArray chamado rows ; em seguida, você armazena suas linhas dentro dessa matriz e armazena os objects Section em uma matriz:

 @interface Section : NSObject { NSMutableArray *rows; } 

Então você simplesmente cria itens de Section , e você pode criar methods dentro de sua class para adicionar / remover itens de linha. Então você empacota todos os itens das Sections dentro de outra matriz:

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

Isso se torna mais útil se você quiser adicionar mais propriedades para cada instância da Section .

A linguagem não tem suporte para arrays multi-dimensionais orientados a objects, mas você pode criar uma class que faça isso usando um NSMutableArray cheio de NSMutableArrays, como o seguinte. Eu não tentei compilar isso ou nada, eu apenas digitei.

 @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 

Você usaria assim:

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

que diabos. Enquanto estivermos revivendo esta questão, aqui está algo para a era da syntax de coleção literal e da interpretação do formato visual!

Caso alguém esteja se perguntando, isso 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: “Oh Hi There James!”

Claro, existe o problema de tentar algo como multi[3][5] = @"?" e obtendo uma exceção de índice inválida, então escrevi uma categoria 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 você pode ver, temos um método de conveniência para fazer um array cheio de NSNull para que você possa definir índices com abandono.

Em segundo lugar, há um método recursivo que analisa uma string com um formato visual como: [3][12] (3 x 12 array). Se sua string for inválida de alguma forma, o método retornará nil , mas se for válido, você receberá um array multidimensional inteiro dos tamanhos que você especificar.

aqui estão alguns exemplos:

 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 

Você pode passar quantas dimensões desejar para o método de formatação visual e acessá-las com a syntax literal, da seguinte forma:

 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 qualquer forma, fez isso mais como um exercício do que qualquer outra coisa; é provavelmente muito eficiente no grande esquema das coisas ... considerando como estamos criando arrays multidimensionais de pointers de object Objective-C.

Graças a Jack pelo seu código, trabalhei um pouco nele; Eu preciso de um nsmutablearray multidimensional para seqüências de caracteres em um dos meu projeto, ele ainda tem algumas coisas que precisam ser corrigidas, mas funciona apenas no momento, eu vou postar aqui, estou aberto para sugestões por favor, porque eu sou apenas um novato no objective c no 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 

Isso está funcionando bem !!!

Eu estou usando atualmente como este

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

Mais uma vez obrigado !!

FYI: O código de Jack precisa de um monte de trabalho antes de funcionar. Entre outros problemas, o autorelease pode fazer com que os dados sejam liberados antes que você os acesse e seu uso chama o método de class arrayWithSections: rows: quando ele é realmente definido como sectionArrayWithSections: rows:

Eu posso tentar postar código de trabalho real mais tarde, se eu tiver uma chance.

Revivendo um thread antigo, mas eu refiz o código de Jack para 1. ele compila e 2. ele está na ordem de arrays 2D [rows] [columns] ao invés de [sections (columns)] [rows] como ele tem. Aqui está!

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 

Foi o que fiz para inicializar o array de arrays.

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

Então mais tarde em um código eu poderia simplesmente:

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