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

Как сохранить 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;
}
4b9b3361

Ответ 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