Как сохранить структуру в NSUserDefaults в Objective-C? - PullRequest
4 голосов
/ 01 ноября 2011

Как сохранить пользовательский struct в NSUserDefaults?

struct Paging {
    NSInteger currentPage;
    NSInteger totalResults;
    NSInteger resultsPerPage;
};

typedef struct Paging Paging;

NSUserDefaults *userInfo = [NSUserDefaults standardUserDefaults];
[userInfo setStruct:paging forKey:@"paging"];
[userInfo synchronize];

Приведенный выше код выдает предупреждение во время выполнения:
*** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value...

Ответы [ 3 ]

5 голосов
/ 22 декабря 2011

В вашем конкретном случае вы можете избежать использования NSData, поскольку участники всего int s, но для будущих читателей этого вопроса, пожалуйста, прочитайте документы Apple по Кодирование иДекодирование типов данных C перед этим!

Кодирование и декодирование типов данных C - структуры и битовые поля :

Вы должны , а не обернуть структуру объектом NSData и архивировать его.Если структура содержит поля объекта или указателя, объект данных не собирается их правильно архивировать .Вы также создаете зависимость от того, как компилятор решает выложить структуру, которая может меняться между версиями компилятора и может зависеть от других факторов. Компилятор не обязан организовывать структуру так, как вы указали ее в исходном коде - могут быть произвольные внутренние и невидимые байты заполнения, например, между полями в структуре и количеством этихМожно менять без уведомления и на разных платформах.Кроме того, любые поля, имеющие несколько байтов шириной , не будут правильно обрабатываться в отношении проблем с порядком байтов. Вы сами создадите себе проблемы с совместимостью.

Этот документ говорит, как правильно это сделать (но, к сожалению, примеры не приводятся - когда я придумаю один, однако,Я обновлю этот ответ на примере):

Лучший способ архивации структуры или набора битовых полей - это архивировать поля независимо и выбрать соответствующий тип метода кодирования / декодирования для каждого .Имена ключей могут быть составлены из имен полей структуры, если хотите, например, "theStruct.order", "theStruct.flags" и так далее.Это создает небольшую зависимость от имен полей в исходном коде, которые со временем могут быть переименованы, но ключи архивации не могут измениться, если вы хотите сохранить совместимость.


Методэто очень похоже на NSData упаковку, но использует NSValue (это также не рекомендуется, но будет работать и для базовых структур):

struct Paging {
    NSInteger currentPage;
    NSInteger totalResults;
    NSInteger resultsPerPage;
};

typedef struct Paging Paging;

- (void)someMeth {
    // Here `paging_struct` is a struct of type `Paging`:
    NSValue *pagingStructValue;
    // On its own line just for readability
    pagingStructValue = [NSValue valueWithBytes:&paging_struct
                                       objCType:@encode(Paging)];

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:pagingStructValue
                     forKey:@"paging"];
    [userDefaults synchronize];
}

NSValue Документация

0 голосов
/ 13 января 2014

Я принял менее благоприятное решение использовать struct в своем приложении для iOS.Теперь я также сталкиваюсь с этой проблемой, когда не могу легко сохранить структуру (которая содержит около 30 переменных) в NSUserDefaults.

После попытки многих решений, представленных на SO и других сайтах, она не работает для меня.Итак, в конце концов я решил создать простой метод для преобразования структуры в NSMutableDictionary.

-(NSMutableDictionary *)structToDictionary:(StructPictures) dat {


    NSArray *values = [NSArray arrayWithObjects:
                       [NSNumber numberWithFloat:dat.bgOpacity],
                       [NSNumber numberWithInt:dat.bgType], // 1= general,
                       [NSNumber numberWithFloat:dat.glowAmt],
                       [NSNumber numberWithInt:dat.textureNum],
                       [NSNumber numberWithInt:dat.patternNum],
                       [NSNumber numberWithInt:dat.patternType],
                       [NSNumber numberWithFloat:dat.patternHue],
                       [NSNumber numberWithFloat:dat.textureSizer],
                       [NSNumber numberWithInt:dat.stickerR],
                       [NSNumber numberWithInt:dat.stickerG],
                       [NSNumber numberWithInt:dat.stickerB]

                       , nil];


    NSArray *keys = [NSArray arrayWithObjects:
                     @"bgOpacity",
                     @"bgType",
                     @"glowAmt",
                     @"textureNum",
                     @"patternNum",
                     @"patternType",
                     @"patternHue",
                     @"textureSizer",
                     @"stickerR",
                     @"stickerG",
                     @"stickerB",
                     nil];

    NSMutableDictionary *res = [[NSMutableDictionary alloc] initWithObjects:values forKeys:keys];

return res;
}

StructPictures - это имя моей структуры (custom).Надеюсь, что это даст альтернативное решение для сохранения структуры в NSUserDefaults.

0 голосов
/ 01 ноября 2011

Один из способов - превратить его в NSData

.
NSData* d = [NSData dataWithBytes: paging length: sizeof(paging)];

В этом случае ваша структура довольно проста, поэтому вы можете добавить категорию в NSUserDefaults, чтобы сохранить и восстановить ее. Я бы реализовал это, сохранив NSDictionary с четырьмя номерами NSN. Немного больше работы, но это означает, что ваш список будет удобочитаем.

...