Как сериализовать массив C с помощью NSCoding?
У меня есть Objective-C класс, который имеет свойство массива C.
И я хочу сериализовать свойство с помощью NSCoding.
@interface TestClass : NSObject <NSCoding>
@property (nonatomic) int* intArray;
@end
@implementation TestClass
-(instancetype)init
{
self = [super init];
if (self) {
_intArray = (int *)malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++) {
_intArray[i] = 0;
}
}
return self;
}
-(void)dealloc
{
free(_intArray);
}
-(instancetype)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
//???
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)coder
{
//???
}
@end
Что я должен написать ???.
Спасибо.
Редактировать:
Спасибо за ответы.
Но что я должен использовать decodeArrayOfObjCType: count: at: или NSData?
Если я не знаю количество выбора, я не могу использовать decodeArrayOfObjCType:кол-во:По: методу?
-(instancetype)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
_itemCount = [coder decodeIntForKey:kItemCount];
_intArray = (int *)malloc(sizeof(int) * _itemCount);
[coder decodeArrayOfObjCType:@encode(int) count:_itemCount at:_intArray];
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeInt:_itemCount forKey:kItemCount];
[coder encodeArrayOfObjCType:@encode(int) count:_itemCount at:_intArray];
}
Или
-(instancetype)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
_itemCount = [coder decodeIntForKey:kItemCount];
NSData *data = [coder decodeObjectForKey:kIntArray];
if (data) {
NSUInteger length = [data length];
_intArray = (int *)malloc(length);
[data getBytes:_intArray length:length];
}
}
return self;
}
-(void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeInt:_itemCount forKey:kItemCount];
if (_intArray) {
NSData *data = [NSData dataWithBytes:_intArray length:sizeof(int) * _itemCount];
[coder encodeObject:data forKey:kIntArray];
}
}
Спасибо.
2 ответа:
Если вы не знаете, сколько значений находится в массиве в момент декодирования, то вы можете использовать
NSData
. Таким образом, у вас может быть два свойства, одно дляintData
, а другое дляcount
элементов в массиве:- (instancetype)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { NSData *data = [coder decodeObjectForKey:kIntArrayKey]; if (data) { NSUInteger length = [data length]; self.count = length / sizeof(int); self.intArray = (int *)malloc(length); [data getBytes:_intArray length:length]; } } return self; } - (void)encodeWithCoder:(NSCoder *)coder { if (_intArray) { NSData *data = [NSData dataWithBytesNoCopy:self.intArray length:sizeof(int) * self.count freeWhenDone:NO]; [coder encodeObject:data forKey:kIntArrayKey]; } }
Или, если вы не хотите использовать
NSData
, Вы можете использоватьencodeBytes:length:forKey:
:- (instancetype)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { NSUInteger length; const uint8_t *bytes = [coder decodeBytesForKey:kIntArrayKey returnedLength:&length]; if (bytes) { self.count = length / sizeof(int); self.intArray = (int *)malloc(length); memcpy(_intArray, bytes, length); } } return self; } - (void)encodeWithCoder:(NSCoder *)coder { if (_intArray) { [coder encodeBytes:(void *)self.intArray length:sizeof(int) * self.count forKey:kIntArrayKey]; } }
Кодирование и декодирование типов данных C руководства по программированию архивов и Сериализаций описывает некоторые дополнительные соображения:
Массивы простых типов
Если вы кодируете массив байтов, вы можете просто использовать предоставленные методы для этого.
Для других арифметических типов создайте объект
NSData
с массивом. Обратите внимание, что в этом случае вы несете ответственность за решение проблем с конечностью платформы. Конечность платформы может быть обработана двумя общими способами. Первый способ заключается в преобразовании элементов массива (точнее, временной копии массива) в каноническую конечность, большую или малую, по одной за раз с функциями, обсуждаемыми в разделе замена байтов в универсальных руководствах по двоичному программированию, второе издание (см. также "порядок байтов" в Справочник по функциям фундамента) и дайте этот результатNSData
в качестве буфера. (Или вы можете записать байты непосредственно с помощьюencodeBytes:length:forKey:
.) Во время декодирования вы должны повернуть процесс вспять, преобразовав большую или малую конечную каноническую форму в текущее представление хоста. Другой метод заключается в использовании массива как есть и записи в отдельном ключевом значении (возможно, логическом), которое было конечным значением хоста при создании архива. Во время декодирования считайте ключ endian и сравните его с endianness текущего хоста и замените значения только в том случае, если они отличаются.Кроме того, вы можете архивировать каждый элемент массива отдельно как их собственный тип, возможно, используя имена ключей, вдохновленные синтаксисом массива, например
“theArray[0]”
,“theArray[1]”
, и так далее. Это не ужасно эффективная техника, но вы можете игнорировать эндианские проблемы.
-(instancetype)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { _intArray = (int *)malloc(sizeof(int) * 5); [coder decodeArrayOfObjCType:@encode(int) count:5 at:_intArray]; } return self; } -(void)encodeWithCoder:(NSCoder *)coder { [coder encodeArrayOfObjCType:@encode(int) count:5 at:_intArray]; }