iOS NSUserDefaults 存储可变数组问题

前言

NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.数组

附:NSUserDefaults 虽然自己不支持自定义对象的存储,不过它支持NSData的类型。因此当咱们要在NSUserDefaults中存储的是自定义的对象的时候,须要将该自定义对象转成NSData存储。而自定义对象转data的方式咱们经过<NSCoding>来实现。这里提早讲到,下面会详细介绍。ui

一、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中进行读取。atom

//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];

 

二、NSUserDefaults 存储自定义对象的问题见上
三、修改存储在NSUserDefaults中的数组

废话很少说上代码,项目中遇到的问题是:spa

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给了解答办法,.net

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的对象会变成不可变的,一样取出来的对象确定是不可变的。code

其它

参考:NSUserDefaults 简介,使用 NSUserDefaults 存储自定义对象对象

相关文章
相关标签/搜索