42

Je dois créer un tableau bidimensionnel mutable dans Objective-C.Tableaux 2D utilisant NSMutableArray

Par exemple, j'ai:

NSMutableArray *sections; 
NSMutableArray *rows; 

Chaque élément de sections se compose d'un tableau rows. rows est un tableau contenant des objets.

Et je veux faire quelque chose comme ceci:

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

Pour avoir quelque chose comme ceci: section 0, lignes: obj1, obj2, obj3 section 1, lignes: obj4, obj5, obj6, obj 7 ...

Existe-t-il un moyen de faire cela en Objective-C?

Répondre

88

D'abord, vous devez allouer et initialiser vos objets avant de les utiliser, quelque chose comme: NSMutableArray * sections = [[NSMutableArray alloc] initWithCapacity:10]; Pour les lignes, vous avez besoin d'un objet pour chacun, pas un seul NSMutableArray * rows;

En second lieu, selon que vous utilisez Xcode 4.4 + (qui a introduit l'indice, à savoir section[i] & section[i] = …) vous devrez peut-être utiliser [sections objectAtIndex:i] pour la lecture et [section replaceObjectAtIndex:i withObject: objectToAdd] pour l'écriture. Troisièmement, un tableau ne peut pas avoir de trous, c'est-à-dire, obj1, nil, obj2. Vous devez fournir un objet réel à chaque index. Si vous ne devez rien mettre, vous pouvez utiliser l'objet NSNull.

De plus, n'oubliez pas que vous pouvez également stocker des objets Objective-C dans les tableaux C simples:

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

+1 pour le type 'id' dans les tableaux C droites. – Tim

+4

Excellente suggestion d'utiliser des tableaux C simples, en particulier lorsque les dimensions de tableau sont connues à l'avance. – timbo

+0

+1 pour inclure à la fois la syntaxe de lecture et d'écriture. –

17

Si vous voulez faire cela en utilisant des tableaux, vous pouvez initialiser votre tableau sections, puis ajoutez un lignes tableau comme suit:

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 vous voulez ajouter cette lignes objet à un certain indice, utilisez ce qui suit:

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

Vous pouvez modifier cette lignes tableau en récupérant le tableau:

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

Vous pouvez toujours créer votre propre membre classe appelée Section, qui a un NSMutableArray appelé rows; alors vous stockez vos lignes à l'intérieur de ce tableau, et stocker les objets Section dans un tableau:

@interface Section : NSObject { 
    NSMutableArray *rows; 
} 

Ensuite, vous créez simplement Section articles, et vous pouvez créer des méthodes dans votre classe pour ajouter/supprimer des éléments de ligne. Ensuite, vous emballez tous les Sections éléments à l'intérieur d'un autre tableau:

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

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

Cela devient plus utile si vous souhaitez ajouter d'autres propriétés pour chaque instance Section.

9

Le langage ne prend pas en charge les tableaux multidimensionnels orientés objet, mais vous pouvez créer une classe qui le fait en utilisant un NSMutableArray complet de NSMabledArrays, comme suit. Je ne l'ai pas essayé de compiler ceci ou quoi que ce soit, je viens tapé dans

@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 

Vous utiliseriez comme ceci:.

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

Pour votre information: le code de Jack a besoin d'un groupe de travail avant qu'il ne fonctionne . Entre autres problèmes, la libération automatique peut provoquer la libération des données avant que vous y accédiez et son utilisation appelle la méthode de classe arrayWithSections: rows: quand elle est réellement définie comme sectionArrayWithSections: rows:

Je peux essayer d'afficher le code de travail réel plus tard si j'ai une chance.

5

Merci à Jack pour son code, j'ai travaillé un peu dessus; J'ai besoin d'un nsmutablearray multidimensionnel pour les cordes dans un de mes projets, il a encore des choses qui doivent être corrigées mais fonctionne uniquement pour le moment, je vais le poster ici, je suis ouvert aux suggestions car je suis juste un débutant dans l'objectif c pour le moment ...

@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 

Cela fonctionne bien !!!

J'utilise actuellement comme cette

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

Merci encore Jack !!

0

Redémarrage d'un ancien thread, mais j'ai retravaillé le code de Jack pour 1. qu'il compile et 2. il est dans l'ordre des tableaux 2D [lignes] [colonnes] au lieu de [sections (colonnes)] [lignes] comme il a-t-il. Voici!

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 
+1

Si vous voulez faire revivre ce vieux thread, au moins utiliser des choses modernes comme la syntaxe tableau littéral, quelques bons liens ici: http://stackoverflow.com/a/13482653/700471 Je pense que vous pouvez même faire quelque chose comme ' myArray [0] [3] ', même si je peux me tromper. –

+0

@MattMc: Merci pour le lien! Je suis assez inexpérimenté dans ce domaine, je pensais juste que je partagerais ce qui a fonctionné pour moi. Je vais certainement vérifier cela. –

+0

Sure chose :) J'ai pris ma propre suggestion et jeta ensemble une méthode qui incorpore la syntaxe littérale et ainsi de suite, de sorte que vous pouvez avoir une idée; c'est ci-dessous. –

6

ce que l'enfer. Tant que nous relançons cette question, voici quelque chose pour l'âge de la syntaxe de la collection littérale et de l'interprétation du format visuel!

Dans le cas où quelqu'un se demande, cela fonctionne:

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

Résultat: "Oh Salut à James!"

Bien sûr, il y a le problème d'essayer quelque chose comme multi[3][5] = @"?" et d'obtenir une exception d'index invalide, alors j'ai écrit une catégorie pour 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 

Comme vous pouvez le voir, nous avons une méthode pratique pour faire une gamme complète de NSNull de sorte que vous pouvez définir des indices avec l'abandon sauvage.

Deuxièmement, il existe une méthode récursive qui analyse une chaîne avec un format visuel tel que: [3][12] (tableau 3 x 12). Si votre chaîne n'est pas valide d'une certaine façon, la méthode retournera nil, mais si elle est valide, vous obtenez un tableau multidimensionnel complet des tailles que vous spécifiez.

Voici quelques exemples:

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 

Vous pouvez passer autant de dimensions que vous le souhaitez dans la méthode de format visuel, et d'y accéder ensuite avec la syntaxe littérale, comme suit:

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

Quoi qu'il en soit, l'a fait plus comme un exercice que toute autre chose; c'est probablement assez efficace dans le grand schéma des choses ... en considérant comment nous fabriquons des tableaux multidimensionnels de pointeurs d'objets Objective-C.

+1

Pour une collection avec des trous, j'utilise 'NSMutableDictionary', où la clé est un ensemble d'index comme ceci:' [dict setObject: o forKey: @ [@ 2, @ 5]] 'De cette façon vous n'obtenez pas NSNull' partout – Tricertops

+0

@iMartin Hm, qu'est-ce que cela fait quand vous appelez 'setObject' avec un tableau comme clé? Définit-il l'objet comme valeur pour chaque clé du tableau? Aussi, je pense que vous voulez faire '@ (2)' pour en faire un nombre, je ne pense pas que ce soit valide sans les parenthèses. –

+0

Il est valide sans '()'. Si vous utilisez un tableau de nombres en tant que clé, l'objet est associé à la combinaison d'index donnée. Rien d'autre. C'est juste une clé normale. – Tricertops

-1

C'est ce que j'ai fait pour initialiser le tableau de tableaux.

NSMutableArray *arrayOfArrays = [[NSMutableArray alloc] initWithCapacity:CONST]; 

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

Puis, plus tard dans un code que je pouvais simplement:

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

1er: vous n'ajoutez rien de nouveau et de précieux à ce sujet. 2ème: si nous parlons de tableaux bidimensionnels en utilisant NSArrays, il faut ajouter comment gérer les entrées vides. – vikingosegundo