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