Свойство для 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];
}