Почему NSUserDefaults не удалось сохранить NSMutableDictionary в iPhone SDK?

Я хотел бы сохранить объект NSMutableDictionary в NSUserDefaults. Тип ключа в NSMutableDictionary равен NSString, тип значения NSArray, который содержит список объектов, который реализует NSCoding. Для каждого документа NSString и NSArray оба соответствуют NSCoding.

Я получаю эту ошибку:

[NSUserDefaults setObject: forKey:]: попытка вставить значение не-свойства.... класса NSCFDictionary.

Любое решение для этого?

Ответ 1

Я обнаружил одну альтернативу, перед сохранением, я кодирую корневой объект (объект NSArray) с помощью NSKeyedArchiver, который заканчивается на NSData. Затем используйте UserDefaults, сохраните NSData.

Когда мне нужны данные, я читаю NSData и использую NSKeyedUnarchiver для преобразования NSData обратно в объект.

Это немного громоздко, потому что мне нужно каждый раз конвертировать в/из NSData, но он просто работает.

Вот один пример для запроса:

Сохранить

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];

Load:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Элемент массива реализует

@interface CommentItem : NSObject<NSCoding> {
    NSString *value;
}

Затем в реализации CommentItem предусмотрено два метода:

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}

У кого-то есть лучшее решение?

Спасибо всем.

Ответ 2

Если вы сохраняете объект в настройках пользователя по умолчанию, все объекты, рекурсивно, полностью вниз, должны быть объектами списка свойств. Соответствие NSCoding здесь ничего не значит - NSUserDefaults не будет автоматически кодировать их в NSData, вы должны сделать это сами. Если ваш "список объектов, который реализует NSCoding" означает объекты, которые не являются объектами списка свойств, тогда вам придется что-то сделать с ними, прежде чем сохранять их по умолчанию.

FYI классы классов свойств NSDictionary, NSArray, NSString, NSDate, NSData и NSNumber. Вы можете записать изменяемые подклассы (например, NSMutableDictionary) в пользовательские настройки, но объекты, которые вы зачитали, всегда будут неизменными.

Ответ 3

Все ваши ключи в словаре NSString s? Я думаю, что они должны быть для того, чтобы сохранить словарь в списке свойств.

Ответ 4

Простой ответ:

NSDictionary - это только объект plist, если клавишами являются NSStrings. Итак, сохраните "Ключ" как NSString с помощью stringWithFormat.


Решение:

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];

Преимущества:

  • Он добавит значение String.
  • Он добавит пустое значение, когда ваше значение переменной NULL.

Ответ 5

Рассматривали ли вы вопрос об использовании протокола NSCoding? Это позволит вам кодировать и декодировать на iPhone два простых метода, которые реализуются с помощью NSCoding. Сначала вам нужно добавить NSCoding в свой класс.

Вот пример:

Это файл .h

@interface GameContent : NSObject <NSCoding>

Затем вам нужно будет реализовать два метода протокола NSCoding.

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
               [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]];
        }
        return self;
    }

    - (void) encodeWithCoder: (NSCoder *)coder
    {
           [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"];
    }

Ознакомьтесь с документацией по NSCoder для получения дополнительной информации. Это очень удобно для моих проектов, где мне нужно сохранить состояние приложения на iPhone, если приложение закрыто и восстановить его обратно, когда оно будет включено.

Ключ должен добавить протокол к интерфейсу, а затем реализовать два метода, которые являются частью NSCoding.

Надеюсь, это поможет!

Ответ 6

Нет лучшего решения. Другой вариант - просто сохранить закодированный объект на диск, но это то же самое. Оба они заканчиваются NSData, который декодируется, когда вы хотите его вернуть.