Подтвердить что ты не робот

2D-массивы с использованием NSMutableArray

Мне нужно создать изменяемый двумерный массив в Objective-C.

Например, у меня есть:

NSMutableArray *sections;
NSMutableArray *rows;

Каждый элемент в sections состоит из массива rows. rows - это массив, содержащий объекты.

И я хочу сделать что-то вроде этого:

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

Чтобы иметь что-то вроде этого: раздел 0, строки: obj1, obj2, obj3 раздел 1, строки: obj4, obj5, obj6, obj 7...

Есть ли способ сделать это в Objective-C?

4b9b3361

Ответ 1

Сначала вы должны выделить и инициализировать свои объекты перед использованием, например: NSMutableArray * sections = [[NSMutableArray alloc] initWithCapacity:10]; Для строк вам нужен один объект для каждого, а не один NSMutableArray * rows;

Во-вторых, в зависимости от того, используете ли вы Xcode 4.4+ (который вводил подписи, a.k.a section[i] и section[i] = …), вам может потребоваться использовать [sections objectAtIndex:i] для чтения и [section replaceObjectAtIndex:i withObject: objectToAdd] для записи.

В-третьих, массив не может иметь отверстий, т.е. obj1, nil, obj2. Вы должны предоставить фактический объект каждому индексу. Если вам ничего не нужно, вы можете использовать NSNull объект.

Кроме того, не забывайте, что вы также можете хранить объекты Objective-C в простых C-массивах:

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

Ответ 2

Если вы хотите сделать это с помощью массивов, вы можете инициализировать массив sections, а затем добавить массив строк следующим образом:

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

Если вы хотите добавить этот объект строк в определенный индекс, используйте следующее:

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

Затем вы можете изменить этот массив строк, извлекая массив:

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

Вы всегда можете создать свой собственный класс под названием Section, который имеет элемент NSMutableArray, называемый rows; то вы сохраняете свои строки внутри этого массива и сохраняете объекты Section в массиве:

@interface Section : NSObject {
    NSMutableArray *rows;
}

Затем вы просто создаете элементы Section, и вы можете создавать методы внутри вашего класса для добавления/удаления элементов строки. Затем вы упаковываете все элементы sections в другой массив:

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

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

Это становится более полезным, если вы хотите добавить дополнительные свойства для каждого экземпляра Section.

Ответ 3

Язык не поддерживает многомерные объектно-ориентированные массивы, но вы можете создать класс, который делает это, используя NSMutableArray, полный NSMutableArrays, например, следующий. Я не пробовал компилировать это или что-то еще, я просто набрал его.

@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

Вы бы использовали его следующим образом:

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

Ответ 4

Какого черта. Пока мы воскрешаем этот вопрос, вот что-то для возраста литерального синтаксиса коллекции и интерпретации визуального формата!

В случае, если кто-то задается вопросом, это работает:

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

Результат: "О, Привет, Джеймс!"

Конечно, есть проблема попробовать что-то вроде multi[3][5] = @"?" и получить недопустимое исключение индекса, поэтому я написал категорию для 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

Как вы можете видеть, у нас есть удобный метод для создания массива, полного NSNull, чтобы вы могли устанавливать индексы с диким отказом.

Во-вторых, существует рекурсивный метод, который анализирует строку с визуальным форматом, например: [3][12] (массив 3 x 12). Если ваша строка некорректна, метод возвращает nil, но если она действительна, вы получаете целый многомерный массив указанных вами размеров.

Вот несколько примеров:

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

Вы можете передать столько измерений, сколько хотите, в метод визуального формата, а затем получить доступ к ним с помощью синтаксиса literal, например:

NSMutableArray *deepTree = [NSMutableArray mutableNullArraysWithVisualFormat:@"[5][3][4][2][7]"];
deepTree[3][2][1][0][5] = @"Leaf";
NSLog(@"Look what at 3.2.1.0.5: %@", deepTree[3][2][1][0][5]);

В любом случае, это было больше упражнением, чем чем-либо еще; это, вероятно, довольно эффективно в грандиозной схеме вещей... учитывая, как мы создаем многомерные массивы указателей объектов Objective-C.

Ответ 5

Спасибо Джеку за его код, я немного поработал над ним; Мне нужен многомерный nsmutablearray для строк в одном из моих проектов, у него все еще есть некоторые вещи, которые нужно исправлять, но работает только в настоящий момент, я отправлю его здесь, я открыт для предложений, потому что я просто начинающий в объективе c в данный момент...

@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

Это нормально работает!!!

В настоящее время я использую его как

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

Еще раз спасибо Jack!!

Ответ 6

FYI: Джек-код нуждается в куче работы до того, как он сработает. Среди других проблем автореферат может привести к тому, что данные будут освобождены до того, как вы получите доступ к нему, а его использование вызывает метод класса arrayWithSections: rows: когда он фактически определен как sectionArrayWithSections: rows:

Я могу попытаться опубликовать фактический рабочий код позже, если я получу шанс.

Ответ 7

Возрождение старого потока, но я переработал код Джека, так что 1. он компилирует и 2. он находится в порядке 2D-массивов [rows] [columns] вместо [section (columns)] [rows], поскольку он Это. Здесь вы идете!

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

Ответ 8

Это то, что я сделал для инициализации массива массивов.

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

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

Затем позже в коде я мог просто:

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