Question

Je dois créer un tableau à deux dimensions mutable en Objective-C.

Par exemple, j'ai:

NSMutableArray *sections;
NSMutableArray *rows;

Chaque élément est constitué d'un sections rows de réseau. rows est un tableau qui contient des objets.

Et je veux faire quelque chose comme ceci:

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

ont quelque chose comme pour ceci: section 0, les lignes: OBJ1, obj2, obj3 section 1, lignes: obj4, obj5, obj6, obj 7 ...

Est-il possible de le faire en Objective-C?

Était-ce utile?

La solution

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 subscripting, a.k.a section[i] & section[i] = …) vous pouvez avoir à utiliser [sections objectAtIndex:i] pour la lecture et l'écriture [section replaceObjectAtIndex:i withObject: objectToAdd] pour.

Troisièmement, un réseau ne peut pas avoir des trous, à savoir, OBJ1, nil, obj2. Vous devez fournir objet réel à chaque index. Si vous avez besoin de rien mettre, vous pouvez utiliser l'objet de NSNull.

En outre, ne pas oublier que vous pouvez également stocker des objets Objective-C dans les tableaux C simples:

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

Autres conseils

Si vous voulez faire cela en utilisant des tableaux, vous pouvez initialiser votre tableau de sections, puis ajoutez un tableau des lignes 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 ensuite modifier ce tableau les lignes 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 classe appelée Section, qui a un membre de 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 des éléments de Section, et vous pouvez créer des méthodes dans votre classe pour ajouter / supprimer des éléments de ligne. Ensuite, vous emballez tous les articles de Sections à 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.

La langue n'a pas de support pour les tableaux orientés objet multidimensionnels, mais vous pouvez faire une classe qui fait à l'aide d'un NSMutableArray plein de NSMutableArrays, comme ce qui 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];

ce que l'enfer. Tant que nous faire revivre cette question, voici quelque chose pour l'âge de la syntaxe de collecte littérale et l'interprétation de 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 non valide, j'ai donc é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.

En second lieu, il y a une méthode récursive qui analyse une chaîne avec un format visuel comme: [3][12] (3 x 12 tableau). Si votre chaîne est invalide en quelque sorte la méthode retourne nil, mais si elle est valide, vous obtenez un tableau multidimensionnel ensemble 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, est-ce plus comme un exercice que toute autre chose; il est probablement assez efficace dans le grand schéma des choses ... considérer comme la façon dont nous faisons des tableaux multidimensionnels de pointeurs d'objet Objective-C.

Merci à Jack pour son code, j'ai travaillé un peu; i besoin d'un NSMutableArray multidimensionnel pour les chaînes dans l'un de mon projet, il a encore des choses qui doivent être fixes mais fonctionne cordes seulement au moment, je vais poster ici, je suis ouvert aux suggestions s'il vous plaît parce que je ne suis qu'un débutant dans c objectif au 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 très bien !!!

Je suis actuellement en utilisant comme ceci

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 !!

Pour votre information: le code de Jack a besoin d'un groupe de travail avant cela fonctionne. Entre autres questions, le autorelease peut provoquer les données à obtenir leur libération avant d'accéder et appelle son utilisation la méthode de classe arrayWithSections: lignes: quand il est réellement défini comme sectionArrayWithSections: lignes:

Je peux essayer d'afficher le code de travail réel plus tard si je reçois une chance.

Redynamiser un vieux fil, mais je retravaillé le code de Jack si 1. il compile et 2. il est dans l'ordre des tableaux 2D c [lignes] [colonnes] au lieu de [sections (colonnes)] [lignes] comme il l'a il. Ici vous allez!

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

est ce que je l'ai fait pour initialiser 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];
scroll top