Как сохранить NSUInteger с помощью NSCoding?
Как сохранить NSUInteger
с помощью протокола NSCoding
, если нет метода на NSCoder
, например -encodeUnsignedInteger:(NSUInteger)anInt forKey:(NSString *)aKey
, например, для NSInteger
?
Следующие работы, но это лучший способ сделать это? Это делает ненужным создание объектов.
@interface MYObject : NSObject <NSCoding> {
NSUInteger count;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:[NSNumber numberWithUnsignedInteger:count] forKey:@"count"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self != nil) {
count = [[decoder decodeObjectForKey:@"count"] unsignedIntegerValue];
}
return self;
}
Ответы
Ответ 1
Проблема в том, что NSUInteger
может быть не того же размера, что и unsigned int
. На многих (если не в большинстве) машинах Mac OS X, NSUInteger
будет unsigned long
, который будет в два раза больше. С другой стороны, ключевой архиватор должен справиться с этим без проблем, поскольку он создает словарь.
Дальнейшим усложнением является тот факт, что NSCoder не имеет методов борьбы с неподписанными типами. Я не могу придумать, как это может привести к потере данных, но для этого потребуются некоторые уродливые броски, а также просто грязные.
Если вы хотите настаивать на неподписанном типе, самым простым способом было бы кодирование необработанных байтов (предпочтительно в порядке сетевого байта с использованием htonl
и ntohl
) в самом большом доступном типе (unsigned long long
) с использованием encodeBytes:length:forKey:
и decodeBytesForKey:returnedLength:
. Для обеспечения максимальной безопасности вы должны проверить длину того, что вы расшифровали, и направить указатель (или использовать объединение), чтобы извлечь тип нужного размера.
Недостатком этого является то, что значение будет представлено в качестве данных, а не целым. Это в основном имеет значение только в том случае, если кто-то решает прочитать в исходных данных plist для вашего архива, а не использовать ключ-сборщик, как вы, и даже тогда только для них. В других случаях, когда это может иметь значение, если Apple (или вы) должны когда-либо переключиться на архитектуру с еще большими целыми типами, типы, размер которых в битах не равен двум (там, по крайней мере, одна старая платформа, где было слово 24 биты) или типы с необычной компоновкой (не большой или малой длины).
Как для вашего решения NSNumber: вы можете взломать свой архив в редакторе списка свойств и посмотреть, что он испустил. Если вывод содержит целочисленный элемент, то он аналогичен использованию encodeInteger:forKey:
. Если выход содержит элемент данных, то он совпадает с решением, упомянутым выше. Чтобы быть тщательным, вы должны проверять выходные данные из каждой поддерживаемой архитектуры.
Ответ 2
NSNumber имеет множество способов хранения/получения типов различного размера и подписей. Это самое простое решение для использования и не требует управления байтами, как предлагают другие ответы.
Ниже приведены типы документации Apple по NSNumber:
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value
- (NSUInteger)unsignedIntegerValue
Да, ваш пример кода - лучший способ кодирования/декодирования NSUInteger. Я бы рекомендовал использовать константы для значений ключей, поэтому вы не ошибаетесь и не вводите ошибки архивирования.
static NSString * const kCountKey = @"CountKey";
@interface MyObject : NSObject <NSCoding> {
NSUInteger count;
}
@end
@implementation MyObject
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:[NSNumber numberWithUnsignedInteger:count] forKey:kCountKey];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self != nil) {
count = [[decoder decodeObjectForKey:kCountKey] unsignedIntegerValue];
}
return self;
}
@end
Ответ 3
Это лучший способ сделать это. Это похоже на ненужную работу, но нет другого доступного типа, который может переносить всю совокупность значений NSUInteger.
Ответ 4
Вы хотите использовать NSCoder
encodeInt:ForKey:
и
decodeIntForKey:
методы. Итак, в вашем случае вам понадобится:
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeInt:count forKey:@"count"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self != nil) {
count = [decoder decodeIntForKey:@"count"];
}
return self;
}
Надеюсь, что это помогает, кроме того, существует гораздо больше кодированных методов "кодирования", посмотрите документацию для NSCoder: D