Свойство для ivar, которое указывает на двумерный массив указателей на строки NSStrings

Я хочу создать класс, который содержит динамический двумерный c-массив указателей на строки NSStrings. Я знаю, что могу смоделировать двумерный массив, используя NSArray, содержащий несколько NSArrays, но если возможно, я бы хотел сделать это, используя традиционный двумерный c-массив. ARC не допустит простого присваивания указателя на NSString элементу c-массива, если вы не используете "__unsafe_unretained":

@interface NumberStringsArray : NSObject
{
  @public
  NSString * __unsafe_unretained **_array;
}

Чтобы избежать утечек памяти и дать объект в собственности класса на каждую NSString, назначенную c-массиву, я добавляю указатель на каждый объект NSString к NSMutableArray. В -(void)dealloc Я освобождаю память, полученную для создания двумерного c-массива.

Вот мой вопрос: как мне объявить свойство на основе _array ivar, чтобы я мог ссылаться на элемент i,j массива как "foobar.array[i][j]", а не "foobar->array[i" ] [у]"?

Позднее усиление: я сделал это очень похоже на ответчика за исключением материала __bridge. Я не знаю, если это имеет значение. Я выделяю двумерный массив здесь:

self->_array = (NSString * __unsafe_unretained **)calloc(_columnCount, sizeof(void *));
if (!self->_array)
  return nil;
for (UINT16 i = 0; i < _columnCount; i++)
{
  self->_array[i] = (NSString * __unsafe_unretained *)calloc(_rowCount, sizeof(void *));
  if (!self->_array[i])
  {
    for (UINT16 a = 0; a < _columnCount; a++)
      if (self->_array[a])
        free(self->_array[a]);
    if (self->_array)
      free(self->_array);
    return nil;
  }
}

Я поместил указатели на объекты NSString в массив, используя подстроки, сгенерированные из файла значений, разделенных запятыми:

NSArray *numbers = [line componentsSeparatedByString: @","];
for (UINT16 i = 0; i < _columnCount; i++)
{
  NSString *number = @"";
  if (i < [numbers count])
    number = [numbers objectAtIndex: i];
  //
  // save it in owners
  //
  [self.owners addObject: number];
  self->_array[i][j] = number;
}

В -(void)dealloc я освобождаю всю память:

-(void)dealloc
{
  for (UINT16 i = 0; i < self.columnCount; i++)
    if (self->_array[i])
      free(self->_array[i]);
  if (self->_array)
    free(self->_array);
}

3 ответа

Решение

Объявите это свойство:

@property (nonatomic) NSString * __unsafe_unretained **_array;

Затем вы можете выделить указатели на объекты:

_array= (NSString * __unsafe_unretained **) malloc(M*sizeof(CFTypeRef) );
for(NSUInteger i=0; i<M;i++)
{
    _array[i]= ((NSString * __unsafe_unretained *) malloc(N*sizeof(CFTypeRef) );
    for(NSUInteger j=0; j<N;j++)
    {
        _array[i][j]= (__bridge NSString*) (__bridge_retained CFTypeRef) [[NSString alloc]initWithCString: "Hello" encoding: NSASCIIStringEncoding];
        // I see that you got habit with C so you'll probably like this method
    }
}

Затем, когда вам это больше не нужно, освободите массив:

for(NSUInteger i=0; i<M; i++)
{
    for(NSUInteger j=0; j<N;j++)
    {
        CFTypeRef string=(__bridge_transfer CFTypeRef) _array[i][j];
    }
    free(_array[i]);
}
free(_array);

Вы не можете, потому что не можете объявить конкретный объект для класса Objective-C. Так

NumberStringsArray object;

не допускается

Вы вынуждены объявить это как

NumberStringsArray *object = [[NumberStringsArray alloc] init.. ];

так что вы должны получить доступ к ивару через правильный -> оператор применяется к указателям. Имейте ввиду, что object.something в Objective-C это просто сокращение для [object something] в то время как в стандартном C вы бы использовали . доступ к полям бетона struct,

(Примечание. Это относится к созданию / использованию свойства для доступа к данным, а не к способу управления данными с помощью обычного управления хранением данных Objective-C или ARC. Размышления об этом причиняют мне боль.)

Если вы хотите, чтобы массив C только для чтения "выглядел" как свойство Objective-C, объявите это свойство, например: @property (readonly, nonatomic) char* myProp; а потом, вместо того, чтобы использовать @synthesize, внедрите для него метод получения в соответствии с:

-(char**)myProp {
    return myPropPointer;
    // Or, if the array is allocated as a part of the instance --
    return &myPropArray[0];
}
Другие вопросы по тегам