Почему 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, который декодируется, когда вы хотите его вернуть.