一、what
数据持久化,就是数据存储。
二、iOS数据存储的方式
有5中方式
- plist文件(XML属性列表)
- preference(偏好设置)
- NSCoding(NSKeyedArchiver归档)
- Sqlite3
- Core Data
三、沙盒
-
每个ios应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件隔离。假设应用的名字叫Layer
模拟器应用沙盒的根路径在: (apple是用户名, 8.0是模拟器版本)
/Users/apple/Library/Application Support/iPhone Simulator/8.0/Applications默认情况下,模拟器的目录是隐藏的,要想显示出来,需要在Mac终端输入下面的命令:
显示Mac隐藏文件的命令:
defaults write com.apple.finder AppleShowAllFiles YES
隐藏Mac隐藏文件的命令:
defaults write com.apple.finder AppleShowAllFiles NO
输完单击Enter键,退出终端,重新启动Finder就可以了重启Finder:鼠标单击窗口左上角的苹果标志-->强制退出-->Finder-->重新启动
3.1 应用程序包应用程序包:(上图中的Layer)包含了所有的资源文件和可执行文件
Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据
Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
四、plist文件
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中。
- (IBAction)saveDataBtnClick:(id)sender {
// youtube做法
// NSString *path = @"/Users/apple/Library/Application Support/iPhone Simulator/7.1/Applications/A6D53E11-DDF0-4392-B2D4-FE77A96888A6/Documents/abc.plist";
// 获取应用程序沙河目录
// NSString *home = NSHomeDirectory();
// 不建议写/
// NSString *path = [home stringByAppendingString:@"/Documents"];
// 不建议Documents写死
// NSString *path = [home stringByAppendingPathComponent:@"Documents"];
// NSUserDomainMask 在用户目录下查找
// YES 代表用户目录的~
// NSDocumentDirectory 查找Documents文件夹
// 建议使用如下方法动态获取
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 拼接文件路径
NSString *path = [doc stringByAppendingPathComponent:@"abc.plist"]
;
NSLog(@"%@", path);
// NSArray *arr = @[@"lnj", @"28"];
// [arr writeToFile:path atomically:YES];
// NSDictionary *dict = @{@"name": @"lnj", @"age":@"28"};
// 调用writeToFile将数据写入文件
// [dict writeToFile:path atomically:YES];
/*
plist只能存储系统自带的一些常规的类, 也就是有writeToFile方法的对象才可以使用plist保存数据
字符串/字典/数据/NSNumber/NSData ...
*/
// 自定义的对象不能保存到plist中
// NJPerson *p = [[NJPerson alloc] init];
// p.name =@"lnj";
// NSDictionary *dict = @{@"person": @"abc"};
[dict writeToFile:path atomically:YES];
}
/**
* 点击读取按钮
*/
- (IBAction)readDataBtnClick:(id)sender {
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [doc stringByAppendingPathComponent:@"abc.plist"]
;
// 读取数据
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"%@", dict);
}
五、偏好设置
- 很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能
每个应用都有个NSUserDefaults实例,通过它来存取偏好设置 - 比如,保存用户名、字体大小、是否自动登录
- (IBAction)saveBtn:(id)sender {
// 偏好设置是专门用来保存应用程序的配置信息的, 一般情况不要再偏好设置中保存其他数据
// 如果利用系统的偏好设置来存储数据, 默认就是存储在Preferences文件夹下面的
// 偏好设置会将所有的数据保存到同一个文件中
// 获取NSUserDefaults对象
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 保存数据(如果设置数据之后没有同步, 会在将来某一时间点自动将数据保存到Preferences文件夹下面)
[defaults setObject:@"lnj" forKey:@"name"];
[defaults setObject:@"man" forKey:@"gender"];
[defaults setInteger:13 forKey:@"age"];
[defaults setDouble:10.1 forKey:@"height"];
// 让NSUserDefaults立刻保存数据
[defaults synchronize];
}
- (IBAction)readBtn:(id)sender {
// 1.获取NSUserDefaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 2.通过NSUserDefaults获取保存的数据
NSString *name = [defaults objectForKey:@"name"];
int age = [defaults integerForKey:@"age"];
NSLog(@"%@", name);
NSLog(@"%d", age);
}
六、归档
- 如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复
- 不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
- NSCoding协议有2个方法:
- encodeWithCoder:
每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量 - initWithCoder:
每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量
person类
person.h
#import
// 如果想将一个自定义对象保存到文件中必须实现NSCoding协议
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) double height;
@end
person.m
#import "Person.h"
@implementation Person
// 当将一个自定义对象保存到文件的时候就会调用该方法
// 在该方法中说明如何存储自定义对象的属性
// 也就说在该方法中说清楚存储自定义对象的哪些属性
- (void)encodeWithCoder:(NSCoder *)encoder
{
NSLog(@"Person encodeWithCoder");
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeInteger:self.age forKey:@"age"];
[encoder encodeFloat:self.height forKey:@"heigth"];
}
// 当从文件中读取一个对象的时候就会调用该方法
// 在该方法中说明如何读取保存在文件中的对象
// 也就是说在该方法中说清楚怎么读取文件中的对象
- (id)initWithCoder:(NSCoder *)decoder
{
NSLog(@"Person initWithCoder");
if (self = [super init]) {
self.name = [decoder decodeObjectForKey:@"name"];
self.age = [decoder decodeIntegerForKey:@"age"];
self.height = [decoder decodeFloatForKey:@"heigth"];
}
return self;
}
@end
ViewController.m
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
- (IBAction)saveBtnClick:(id)sender;
- (IBAction)readBtnClick:(id)sender;
@end
@implementation ViewController
- (IBAction)saveBtnClick:(id)sender {
// 1.创建对象
Person *p = [[Person alloc] init];
p.name = @"zhangsan";
p.age = 28;
p.height = 1.76;
// 2.获取文件路径
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [docPath stringByAppendingPathComponent:@"stu.xxoo"];
NSLog(@"path = %@", path);
// 3.将自定义对象保存到文件中
[NSKeyedArchiver archiveRootObject:p toFile:path];
}
- (IBAction)readBtnClick:(id)sender {
// 1.获取文件路径
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [docPath stringByAppendingPathComponent:@"stu.xxoo"];
// 2.从文件中读取对象
NJPerson *p = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSLog(@"%@ %d %.1f %.1f", stu.name, stu.age, stu.height, stu.weight);
}
@end
七、SQLite
- SQLite3是一款开源的嵌入式关系型数据库,可移植性好、易使用、内存开销小
- SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中。比如下列的创表语句是合法的:
create table t_person(name, age);
为了保证可读性,建议还是把字段类型加上:
create table t_person(name text, age integer); - SQLite3常用的5种数据类型:text、integer、float、boolean、blob
- 在iOS中使用SQLite3,首先要添加库文件libsqlite3.dylib和导入主头文件
- SQLite3的使用
- 原生的SQLite API在使用上大部分都是C语言代码,在使用时,非常不便,因此便出现了很多针对SQLite封装的第三方框架,其中FMDB就是其中一个优秀的框架
FMDB的使用
另外一位简友写的不错
FMDB的使用方法(附Demo)
八、CoreData
Core Data框架提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite3数据库文件中,也能够将保存在数据库中的数据还原成OC对象。在此数据操作期间,不需要编写任何SQL语句。使用此功能,要添加CoreData.framework和导入主头文件
- CoreData的使用
- IOS之分析网易新闻存储数据(CoreData的使用,增删改查)