这篇文章主要讲述NSUserDefaults的简单使用
Demo地址
对应实现的文件是NSUserDefaultViewController.m文件和person.m文件
存储数据成功后,在沙盒中查看相应的存储文件数据如下图所示:
注意,NSUserDefaults除了存储一些基本的数据类型之外,还可以存储NSArray、NSDictionary等一些基本的数据类型,如果想要存储自定的数据类型,执行将自定义对象转化为NSData,然后使用NSUserDefaults存储,上图中Person就是自定义对象,注意,每次读取获得的数据类型都是不可变类型,例如,你存储进去的是NSMutableArray类型,但是读取出来之后就是NSArray类型
如何查看app的沙盒文件
模拟机
在这里,先说一下,如何查看文件存储的沙盒位置
如果是使用xcode提供的模拟机,那么文件就在自己电脑上,使用
//获取沙盒根目录
NSString *directory = NSHomeDirectory();
NSLog(@"directory:%@", directory);
这样可以获得app沙盒文件的根目录
真机
如果使用的是真机测试
在xcode中,点击windows->Devices And Simulators,找到我们对应的app名称
选中,点击下方的齿轮
点击Download Container即可将app的沙盒文件下载到电脑上,然后可以查看
NSUserDefaults实现
首先定义两个按钮,一个用于写入数据,一个用于读取数据
在NSUserDefaultViewController.h文件中
@property (nonatomic, strong) UIButton *NSUserDefaultWriteButton;
@property (nonatomic, strong) UIButton *NSUserDefaultReadButton;
之后,在.m中实现相应的懒加载和布局
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = @"NSUserDefault存储";
self.navigationController.navigationBar.translucent = NO;
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.NSUserDefaultWriteButton];
[self.NSUserDefaultWriteButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view);
make.centerY.equalTo(self.view);
make.width.greaterThanOrEqualTo(@0);
make.height.equalTo(@30);
}];
[self.view addSubview:self.NSUserDefaultReadButton];
[self.NSUserDefaultReadButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view);
make.top.equalTo(self.NSUserDefaultWriteButton.mas_bottom).offset(20);
make.width.greaterThanOrEqualTo(@0);
make.height.equalTo(@30);
}];
}
- (UIButton *)NSUserDefaultWriteButton {
if (_NSUserDefaultWriteButton) {
return _NSUserDefaultWriteButton;
}
_NSUserDefaultWriteButton = [[UIButton alloc] initWithFrame:CGRectZero];
_NSUserDefaultWriteButton.titleLabel.font = [UIFont systemFontOfSize:18];
[_NSUserDefaultWriteButton setTitle:@"NSUserDefault写入数据" forState:UIControlStateNormal];
[_NSUserDefaultWriteButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_NSUserDefaultWriteButton addTarget:self action:@selector(nsUserDefaultWirteData) forControlEvents:UIControlEventTouchUpInside];
return _NSUserDefaultWriteButton;
}
- (UIButton *)NSUserDefaultReadButton {
if (_NSUserDefaultReadButton) {
return _NSUserDefaultReadButton;
}
_NSUserDefaultReadButton = [[UIButton alloc] initWithFrame:CGRectZero];
_NSUserDefaultReadButton.titleLabel.font = [UIFont systemFontOfSize:18];
[_NSUserDefaultReadButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_NSUserDefaultReadButton setTitle:@"NSUserDefault读出数据" forState:UIControlStateNormal];
[_NSUserDefaultReadButton addTarget:self action:@selector(nsUserDefaultReadData) forControlEvents:UIControlEventTouchUpInside];
return _NSUserDefaultReadButton;
}
- (void)nsUserDefaultWirteData {
NSLog(@"NSUserDefault写入数据");
}
- (void)nsUserDefaultReadData {
NSLog(@"NSUserDefault读出数据");
}
之后,我们就可以在按钮对应的点击方法中实现存储数据和读取数据
接下来一个一个说
先获取到唯一的NSUserDefaults对象
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
存储的代码写在nsUserDefaultWirteData方法中,读取的代码写在nsUserDefaultReadData中
1.整数
//存储整数
[ud setInteger:111 forKey:@"INT"];
//读取NSInteger
NSInteger i = [[ud objectForKey:@"INT"] integerValue];
NSLog(@"i = %ld",(long)i);
2.BOOL值
//存储bool值
[ud setBool:YES forKey:@"BOOL"];
//读取bool值
BOOL isYES = [ud objectForKey:@"BOOL"];
NSLog(@"isYES = %d",isYES);
3.浮点数
//存储浮点数
[ud setFloat:1.8 forKey:@"float"];
//读取浮点数
CGFloat f = [[ud objectForKey:@"float"] floatValue];
NSLog(@"f = %f",f);
4.NSString字符串
//存储字符串NSString
[ud setObject:@"落叶兮兮" forKey:@"Name"];
//读取NSString
NSString *name = [ud objectForKey:@"Name"];
NSLog(@"name = %@",name);
5.NSNumber
//存储NSNumber
NSNumber *num = [NSNumber numberWithInteger:100];
[ud setObject:num forKey:@"NUM"];
//读取NSNumber
NSNumber *number = [ud objectForKey:@"NUM"];
NSLog(@"number = %@",number);
6.数组NSArray
//存储数组
NSArray *array = [NSArray arrayWithObjects:@"11",@"22",@"33",nil];
[ud setObject:array forKey:@"ARRAY"];
//读取NSArray
NSArray *arr = [ud objectForKey:@"ARRAY"];
NSLog(@"arr = %@",arr);
7.字典NSDictionary
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setValue:@"落叶兮兮" forKey:@"Id1"];
[dic setValue:@"雪花飞舞" forKey:@"Id2"];
[ud setObject:dic forKey:@"Dictionary"];
//读取NSDictionary
NSDictionary *dic = [ud objectForKey:@"Dictionary"];
NSLog(@"dic id1 = %@",[dic objectForKey:@"Id1"]);
NSLog(@"dic id2 = %@",[dic objectForKey:@"Id2"]);
注意,NSUserDefaults读取后的类型都是不可变的类型
还有其他的一些基本数据类型,比如NSDate,Double等,这里就不再写了,下面主要讲自定义对象的存储,这部分比较复杂
自定义对象Person
对于NSUserDefault存储自定义对象,相比其他类型,这部分是最复杂的,将这部分放在最后再写
我们都知道,存储自定义对象,应该将对象转换为NSData数据类型,然后将其存储到plist文件中,这里转换需要用到NSKeyedArchiver归档和NSKeyedUnarchiver解档
首先,我们新建一个文件,命名为Person
定义基本的属性和赋值方法
在person.h文件中,
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
- (void)setName:(NSString *)name age:(NSInteger)age;
在person.m文件中,
- (void)setName:(NSString *)name age:(NSInteger)age {
self.name = name;
self.age = age;
}
这样基本类Person就定义好了,在NSUserDefaultViewController中初始化并赋值
在nsUserDefaultWriteData方法中
Person *person = [[Person alloc] init];
[person setName:@"落叶兮兮" age:24];
之后,将Person转化为NSData对象
//使用error接收错误信息,一旦出错,error里面存储的就是错误信息
NSError *error = nil;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:&error];
if (error) {
NSLog(@"写入数据时转换失败,失败的原因是%@",error);
}
运行之后,报错
原因是Person类没有实现NSSecureCoding协议,关于这个协议方法,主要是为了数据安全,防止被别人篡改,具体的可以去苹果官方文档查看
接下来就很简单了,我们需要实现相应的协议方法
person类遵守
@interface Person : NSObject
点进去可以看到NSSecureCoding协议遵守
所以需要实现NSCoding协议的方法
在Person.m文件中
//1.编码方法
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"PersonName"];
[aCoder encodeInteger:self.age forKey:@"PersonAge"];
}
//2.解码方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
self.name = [aDecoder decodeObjectForKey:@"PersonName"];
self.age = [aDecoder decodeIntegerForKey:@"PersonAge"];
}
return self;
}
注意,根据NSSecureCoding协议的介绍,我们必须实现supportsSecureCoding方法,并且返回YES,这样才是支持NSSecureCoding协议
而且必须得是类方法,刚开始我写成了实例方法,结果一直报错,转化失败
+ (BOOL)supportsSecureCoding {
NSLog(@"执行了这个方法");
return YES;
}
此事执行转化方法,发现没有错误出现,接下来是读取,读取获得的是NSData对象,需要将其转化为Person自定义对象,使用解档
NSData *data = [ud objectForKey:@"Person"];
Person *person = [[Person alloc] init];
NSError *error = nil;
person = [NSKeyedUnarchiver unarchivedObjectOfClass:[Person class] fromData:data error:&error];
if (error) {
NSLog(@"转化出错,出错的原因为%@",error);
}
NSLog(@"person name = %@",person.name);
NSLog(@"person age = %ld",(long)person.age);
运行之后发现能够正常输出内容,转化类型无错误发生
9.存储路径
//NSUserDefault写入数据,默认放在library/Preferences文件夹下,以.plist文件存放
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
NSLog(@"数据持久化的路径为:%@",path);
最好使用模拟机运行,模拟机运行之后获得path,直接在finder中command+G可以直接到存储的plist文件
如果使用真机,需要将数据包下载到电脑上才能看到,比较麻烦
总结
最终的数据存储图为:
Demo地址
对应实现的文件是NSUserDefaultViewController.m文件和person.m文件
总结
iOS开发中数据持久化总结(一)
iOS开发中数据持久化总结(二):NSUserDefault实现数据存储
ios开发中数据持久化总结(三):NSKeyArchive归档解档的实现
ios开发中数据持久化总结(四):使用FMDataBase存储数据