Tablice 2D przy użyciu NSMutableArray

Muszę stworzyć zmienną dwuwymiarową tablicę w Objective-C.

Na przykład mam:

NSMutableArray *sections;
NSMutableArray *rows;

Każdy element w sections składa się z tablicy rows. rows jest tablicą zawierającą obiekty.

A ja chcę zrobić coś takiego:

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

Aby mieć coś takiego: sekcja 0, wiersze: obj1, obj2, obj3 sekcja 1, wiersze: obj4, obj5, obj6, obj 7...

Czy jest na to sposób w Objective-C?

Author: Josh Caswell, 2009-04-07

8 answers

Najpierw musisz przydzielić i zainicjalizować swoje obiekty przed użyciem, coś w stylu: NSMutableArray * sections = [[NSMutableArray alloc] initWithCapacity:10]; dla wierszy potrzebujesz jednego obiektu dla każdego, a nie jednego NSMutableArray * rows;

Po drugie, w zależności od tego, czy używasz Xcode 4.4+ (który wprowadził subscripting, a. K. a section[i] & section[i] = …) Być może będziesz musiał użyć [sections objectAtIndex:i] do czytania i [section replaceObjectAtIndex:i withObject: objectToAdd] do pisania.

Po Trzecie, tablica nie może mieć otworów, np. obj1, nil, obj2. Musisz podać rzeczywisty obiekt do każdego indeksu. Jeśli nie trzeba nic umieścić, można użyć NSNull obiekt.

Ponadto, nie zapominaj, że możesz również przechowywać Obiekty Objective - C w zwykłych tablicach C:

id table[lnum][rnum];
table[i][j] = myObj;
 88
Author: mouviciel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-07 11:24:48

Jeśli chcesz to zrobić za pomocą tablic, możesz zaintializować swoją tablicę sections, a następnie dodać tablicę rows w następujący sposób:

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

Jeśli chcesz dodać obiekt rows do określonego indeksu, użyj następującego polecenia:

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

Możesz zmodyfikować tablicę wierszy, pobierając tablicę:

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

Zawsze możesz utworzyć własną klasę o nazwie Section, która ma element NSMutableArray o nazwie rows; następnie przechowujesz swoje wiersze wewnątrz tej tablicy, a obiekty Section w tablica:

@interface Section : NSObject {
    NSMutableArray *rows;
}

Następnie po prostu tworzysz Section elementy i możesz tworzyć metody wewnątrz swojej klasy, aby dodawać/usuwać elementy wiersza. Następnie pakujesz wszystkie Sections elementy do innej tablicy:

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

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

Staje się to bardziej przydatne, jeśli chcesz dodać więcej właściwości dla każdej instancji Section.

 17
Author: Alex Rozanski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-07 09:31:04

Język nie obsługuje wielowymiarowych tablic obiektowych, ale można utworzyć klasę, która to zrobi, używając nsmutablearray pełnego nsmutablearrays, jak poniżej. Nie próbowałem tego kompilować, tylko wpisałem.

@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

Użyłbyś tego tak:

SectionArray *a = [SectionArray arrayWithSections:10 rows:5];
[a setObject:@"something" inSection:4 row:3];
id sameOldSomething = [s objectInSection:4 row:3];
 9
Author: Jack Nutting,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-07 10:14:01

A co mi tam. Dopóki ożywiamy to pytanie, oto coś dla epoki dosłownej składni kolekcji i wizualnej interpretacji formatu!

W razie gdyby ktoś się zastanawiał, to działa:

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

Wynik: "Oh Hi There James!"

Oczywiście, jest problem z próbą czegoś takiego jak multi[3][5] = @"?" i uzyskaniem nieprawidłowego wyjątku indeksu, więc napisałem kategorię dla 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

Jak widać, mamy wygodną metodę tworzenia tablicy pełnej z NSNull, dzięki czemu można ustawić indeksy z dziką

Po drugie, istnieje metoda rekurencyjna, która parsuje ciąg znaków w formacie wizualnym, takim jak: [3][12] (Tablica 3 x 12). Jeśli łańcuch znaków jest nieprawidłowy, metoda zwróci nil, ale jeśli jest poprawny, otrzymasz całą wielowymiarową tablicę rozmiarów, które podasz.

Oto kilka przykładów:

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

Możesz przekazać dowolną liczbę wymiarów do metody formatowania wizualnego, a następnie uzyskać do nich dostęp za pomocą dosłownego składnia tak:

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

W każdym razie, zrobiłem to bardziej jako ćwiczenie niż cokolwiek innego; prawdopodobnie jest to dość skuteczne w wielkim schemacie rzeczy...biorąc pod uwagę, jak tworzymy wielowymiarowe tablice wskaźników obiektów Objective-C.

 6
Author: Matt Mc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-07 06:19:28

Dzięki Jackowi za jego kod, pracowałem nad nim trochę; potrzebuję wielowymiarowego nsmutablearray dla strun w jednym z moich projektów, nadal ma kilka rzeczy, które muszą być naprawione, ale działa struny tylko w tej chwili, będę pisać go tutaj, jestem otwarty na sugestie proszę bo jestem tylko początkujący w objective c w tej chwili...

@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
To działa dobrze !!!

Obecnie używam go w ten sposób

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

Jeszcze raz dzięki Jack !!

 5
Author: Jericho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-17 15:50:32

Dla twojej informacji: Kod Jacka wymaga sporo pracy, zanim zadziała. Wśród innych problemów, autorelease może spowodować, że dane zostaną zwolnione, zanim uzyskasz do nich dostęp, a jego użycie wywoła metodę klasy arrayWithSections: rows: gdy jest faktycznie zdefiniowana jako sectionArrayWithSections: rows:

Mogę spróbować opublikować rzeczywisty kod roboczy później, jeśli będę miał okazję.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-07 00:57:54

Ożywiam Stary wątek, ale przerobiłem Kod Jacka na 1. kompiluje i 2. jest w kolejności 2D C tablic [rows] [columns] zamiast [sections (columns)] [rows] jak to ma. Proszę bardzo!

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
Author: Matt Cooper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-07 04:16:40

To właśnie zrobiłem, aby zainicjować tablicę tablic.

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

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

Potem w kodzie mógłbym po prostu:

[[arrayOfArrays objectAtIndex:0] addObject:myObject];
 -1
Author: Mantvydas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-09 13:27:04