NSUserDefaults 存储可变数组问题
前言
NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.
附:NSUserDefaults 虽然本身不支持自定义对象的存储,不过它支持NSData的类型。所以当我们要在NSUserDefaults中存储的是自定义的对象的时候,需要将该自定义对象转成NSData存储。而自定义对象转data的方式我们通过<NSCoding>来实现。这里提前讲到,下面会详细介绍。
1、NSUserDefaults 存储数组问题
①如果数组中的对象不是自定义的对象,那么可直接存储。如:
NSArray *array = @[@"1", @"2", @"3", @"4"];
[[NSUserDefaults standardUserDefaults] setObject:array forKey:@"key"];
[[NSUserDefaults standardUserDefaults] synchronize];
②如果数组中的对象是自定义的对象,那么需要先让这个自定义类实现<NSCoding>协议中的- (id) initWithCoder: (NSCoder *)coder方法和- (void) encodeWithCoder: (NSCoder *)coder方法,然后把该自定义的类对象编码到NSData中,再从NSUserDefaults中进行读取。
//User.h
@interface User : NSObject<NSCoding> //注意:这里需要实现NSCoding协议
@property (nonatomic, copy) NSString *realName;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, copy) NSString *password;
@end
//User.m
@implementation User
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
self.realName = [aDecoder decodeObjectForKey:@"realName"];
self.nickName = [aDecoder decodeObjectForKey:@"nickName"];
self.password = [aDecoder decodeObjectForKey:@"password"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.realName forKey:@"realName"];
[aCoder encodeObject:self.nickName forKey:@"nickName"];
[aCoder encodeObject:self.password forKey:@"password"];
}
@end
这时,存储自定义对象的数组的获取与保存方法如下
//存储
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSArray *array = @[customObject1, customObject2, customObject3, customObject4];
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:array];
[userDefaults setObject:arrayData forKey:@"arrayKey"];
[userDefaults synchronize];
//取出
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSData *arrayData = [userDefaults objectForKey:@"arrayKey"];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:arrayData];
2、NSUserDefaults 存储自定义对象的问题见上
3、修改存储在NSUserDefaults中的数组
废话不多说上代码,项目中遇到的问题是:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *array = [userDefaults objectForKey:@"theArrayKey"]];
[array addObject:@"some new value"];
[userDefaults setObject: array forKey:@"theArrayKey"]; //会卡住主程序
[[NSUserDefaults standardUserDefaults] synchronize];
这句话取出了数组,可是当对数组添加元素后,进行存储时卡在了下面这句话:
[userDefaults setObject: array forKey:@"theArrayKey"];
时候会把主线程卡住,但是不崩溃,不知道为何,就Google了,stackoverflow给了解答办法,
When you store mutable objects to NSUserDefaults, it stores an immutable copy of it so you can't change it directly like that. You have to get the mutable copy out of defaults, change it, and then set it back, replacing old object in defaults.
即:修改存储在NSUserDefaults中的数组:我们从NSUserDefaults中取出的数组是不可变的(因为NSUserDefaults 存储的对象全是不可变的)。所以当我们需要修改存储在NSUserDefaults中的数组时,需要用一个新的可变数组来保存之前的值,再修改,之后再保存,即修改的过程应该如下:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *array = [userDefaults objectForKey:@"theArrayKey"]];
NSMutableArray *mutableCopyArray = [array mutableCopy]; //重要步骤操作mutableCopyArray
[mutableCopyArray addObject:@"some new value"];
[userDefaults setObject: mutableCopyArray forKey:@"theArrayKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
总结:NSUserDefaults 存储的对象全是不可变的(这一点非常关键,弄错的话程序会出bug),即存进NSUserDefaults的对象会变成不可变的,同样取出来的对象肯定是不可变的。