Почему NSUserDefaults не удалось сохранить NSMutableDictionary в iOS?
Я хотел бы сохранить NSMutableDictionary
объект в NSUserDefaults
, Тип ключа в NSMutableDictionary
является NSString
тип значения NSArray
, который содержит список объектов, которые реализует NSCoding
, За документ, NSString
а также NSArray
оба соответствуют NSCoding
,
Я получаю эту ошибку:
[NSUserDefaults setObject: forKey:]: Попытка вставить значение не-свойства.... класса NSCFDictionary.
6 ответов
Я нашел одну альтернативу, перед сохранением кодирую корневой объект (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;
}
У кого-нибудь есть лучшее решение?
Спасибо всем.
Если вы сохраняете объект в пользовательских настройках по умолчанию, все объекты, рекурсивно, до самого конца, должны быть объектами списка свойств. Соответствие NSCoding здесь ничего не значит. NSUserDefaults
не будет автоматически кодировать их в NSData
Вы должны сделать это сами. Если ваш "список объектов, который реализует NSCoding
"означает объекты, которые не являются объектами списка свойств, тогда вам придется что-то с ними делать, прежде чем сохранять их по умолчанию.
К вашему сведению классы списка свойств NSDictionary
, NSArray
, NSString
, NSDate
, NSData
, а также NSNumber
, Вы можете написать изменяемые подклассы (например, NSMutableDictionary
) к пользовательским настройкам, но объекты, которые вы читаете, всегда будут неизменными.
Все ваши ключи в словаре NSString
s? Я думаю, что они должны быть для того, чтобы сохранить словарь в список свойств.
Самый простой ответ:
NSDictionary
является только объектом plist, если ключи являются NSStrings. Итак, Храните "Ключ" как NSString
с stringWithFormat
,
Решение:
NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];
Выгоды:
- Это добавит String-Value.
- Это добавит пустое значение, когда ваше значение переменной
NULL
,
Рассматривали ли вы вопрос о реализации 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
,
Надеюсь, это поможет!
Нет лучшего решения. Другой вариант - просто сохранить закодированный объект на диск - но это делает то же самое. Они оба заканчивают с NSData, который декодируется, когда вы хотите его вернуть.