Почему NSUserDefaults не удалось сохранить NSMutableDictionary в iOS? - PullRequest
145 голосов
/ 23 января 2009

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

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

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

Ответы [ 6 ]

229 голосов
/ 23 января 2009

Я нашел одну альтернативу, перед сохранением я кодирую корневой объект (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];

Нагрузка:

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;
}

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

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

105 голосов
/ 23 января 2009

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

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

14 голосов
/ 23 января 2009

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

7 голосов
/ 04 февраля 2013

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

NSDictionary - это только объект списка , если ключи - NSStrings . Таким образом, сохраните "Ключ" как NSString с stringWithFormat.


Решение:

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

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

  1. Будет добавлено String-Value .
  2. Будет добавлено Пустое значение , если значение переменной равно NULL.
5 голосов
/ 25 января 2009

Рассматривали ли вы вопрос реализации протокола 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.

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

0 голосов
/ 24 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...