DataPersistence(数据持久化)
1.数据持久化?
数据永久的保存
2.为什么要做数据持久化?
要把之前的操作(存档, 记录等)保存起来
3.为什么数据之前保存不了呢?
以前的数据都存在内存中, 程序一旦终止, 内存就会被收回
4.数据保存到哪里, 才能做数据持久化
把数据存到硬盘里
5.存到硬盘的哪个位置呢?
沙盒机制: iOS会为每一个应用, 单独创建一个文件夹(沙盒), 这个文件夹只允许当前应用访问
6.如何通过代码获取路径?
7.沙盒文件夹又分了多个子文件夹, 为什么?
Finder cmd+shift+g 前往文件夹
子文件夹方便对文件进行管理, 每个文件夹都有不同的作用
8.如何进行数据持久化?
数据持久化的方式:
a.文件读写, 支持数组, 字典, 字符串, NSData, 支持这4种类型的嵌套
b.NSUserDefault, 单例, 支持基本数据类型 + 对象 + URL
c.归档, 支持所有类型, 前提, 遵守<NSCoding>协议, 实质: 把数据转成NSData类型, 再把NSData的数据写入文件
d.数据库
e.CoreData
9.完整的数据持久化过程
a.启动程序后, 从沙盒文件夹中读取文件内容
b.将内容在合适的控件上展示
c.如果对内容修改, 应该吧内容存到文件中
a.文件读写, 支持数组, 字典, 字符串, NSData, 支持这4种类型的嵌套
#import "ViewController.h"
@interface ViewController ()<UITextFieldDelegate>
@property (retain, nonatomic) IBOutlet UITextField *userName;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
沙盒路径
NSLog(@"%@", NSHomeDirectory());
// [NSString stringWithFormat:@"%@/Documents", NSHomeDirectory()];
Documents, 文档文件夹, 存放重要的文件(用户配置信息, 存档等), 并且手机连电脑进行同步时, 会同步此文件夹; 文件夹中存的文件体积不能过大
参数1: 搜索的文件夹名字
参数2: 搜索区域
参数3: 相对路径(NO)还是绝对路径(YES)
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO) firstObject];
NSLog(@"%@", documentsPath);
Library, 资源文件夹, 存放资源文件(图片, 音频, 视频等)
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
NSLog(@"%@", libraryPath);
tmp, 临时文件夹, 存过渡文件(压缩包)
NSLog(@"%@", NSTemporaryDirectory());
*.app, 应用包(文件夹), 存放编译过后的文件(可执行文件, nib)和工程资源, 这个文件夹是只读的
NSLog(@"%@", [[NSBundle mainBundle] bundlePath]);
[self method2];
[self method3];
[self method4];
[self method5];
[self method6];
}
NSString写入
- (void)method1 {
文件读写, 支持: NSString, NSArray, NSDictionary
如果文件不存在, 就创建文件, 并把内容写入文件
如果文件存在, 覆盖文件内容
//NSString的写入
NSString *userName = self.userName.text;
//参数1: 文件路径
//参数2: 是否使用辅助文件
//参数3: 文字编码格式
//参数4: 是否有错误 error
NSString *string = [NSString stringWithFormat:@"%@/aaa.text", NSHomeDirectory()];
NSError *error = nil;
BOOL result = [userName writeToFile:string atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (result) {
NSLog(@"写入成功");
} else {
NSLog(@"写入失败: %@", error);
}
}
NSString读取
- (void)method2 {
NSError *error = nil;
NSString *string = [[[NSString alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/aaa.text", NSHomeDirectory()] encoding:NSUTF8StringEncoding error:&error] autorelease];
if (error) {
NSLog(@"读取失败:%@", error);
} else {
self.userName.text = string;
}
}
NSArray的写入
- (void)method3 {
NSArray *array = @[@"袜子", @"越南新娘", @"衣服", @"万能胶"];
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
字符串路径, 保证两个字符串之间有一个"/"
NSString *filePath = [documentPath stringByAppendingPathComponent:@"array.plist"];
//字符串后缀拼接, 保证两个字符串之间有一个"."
// NSString *filePath = [documentPath stringByAppendingPathExtension:@"txt"];
NSLog(@"%@", filePath);
注: 写入和读取操作, 必须使用绝对路径
BOOL result = [array writeToFile:[NSString stringWithFormat:filePath, documentPath] atomically:YES];
if (result) {
NSLog(@"写入成功!");
} else {
NSLog(@"写入失败!");
}
}
NSArray读取操作
- (void)method4 {
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:[documentPath stringByAppendingPathComponent:@"array.plist"]];
NSLog(@"%@", array);
[array release];
}
NSDictionary写入
- (void)method5 {
NSDictionary *dic = @{@"name": @"张三", @"gender": @"男"};
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
NSString *string = [libraryPath stringByAppendingPathComponent:@"dic.plist"];
NSLog(@"%@", string);
BOOL result = [dic writeToFile:string atomically:YES];
if (result) {
NSLog(@"写入成功");
} else {
NSLog(@"写入失败");
}
}
NSDictionary读取
- (void)method6 {
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) firstObject];
NSString *string = [libraryPath stringByAppendingPathComponent:@"dic.plist"];
NSDictionary *dic = [[NSDictionary alloc] initWithContentsOfFile:string];
NSLog(@"%@", dic);
[dic release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
[_userName release];
[super dealloc];
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self method1];
//键盘回收
[textField resignFirstResponder];
return YES;
}
@end
b.NSUserDefault, 单例, 支持基本数据类型 + 对象 + URL
#import "OneViewController.h"
@interface OneViewController ()
@end
@implementation OneViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self method1];
[self method2];
}
NSUserDefualts的写入
- (void)method1 {
NSUserDefaults, 支持数据持久化的单例类, NSUserDefualts对应一个文件
NSLog(@"%@", NSHomeDirectory());
NSUserDefaults *userDefualts = [NSUserDefaults standardUserDefaults];
//存数据
[userDefualts setObject:@"哈哈" forKey:@"string"];
[userDefualts setBool:YES forKey:@"bool"];
[userDefualts setFloat:3.14 forKey:@"float"];
[userDefualts setURL:[NSURL URLWithString:@"www.baidu.com"] forKey:@"url"];
把内容同步到文件中
[userDefualts synchronize];
}
NSUserDefualts的读取
- (void)method2 {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *string = [userDefaults objectForKey:@"string"];
NSLog(@"%@", string);
BOOL result = [userDefaults boolForKey:@"bool"];
NSLog(@"%d", result);
float number = [userDefaults floatForKey:@"float"];
NSLog(@"%.2f", number);
NSURL *url = [userDefaults URLForKey:@"url"];
NSLog(@"%@", url);
}
c.归档, 支持所有类型, 前提, 遵守<NSCoding>协议, 实质: 把数据转成NSData类型, 再把NSData的数据写入文件
Person.m
#import "Person.h"
@implementation Person
- (void)dealloc
{
[_name release];
[_gender release];
[_age release];
[super dealloc];
}
- (NSString *)description
{
return [NSString stringWithFormat:@"name: %@ gender: %@ age: %@", _name, _gender, _age];
}
#pragma mark - NSCoding
对这个类的属性进行编码(归档)
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.gender forKey:@"gender"];
[aCoder encodeObject:self.age forKey:@"age"];
}
对这个类的属性进行解码(反归档)
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.gender = [aDecoder decodeObjectForKey:@"gender"];
self.age = [aDecoder decodeObjectForKey:@"age"];
}
return self;
}
@end
#import "TwoViewController.h"
#import "Person.h"
@interface TwoViewController ()
@end
@implementation TwoViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self method1];
[self method2];
}
归档
前提: 能够归档的类, 必须遵守<NSCoding>协议
- (void)method1 {
//数据
Person *person = [[Person alloc] init];
person.name = @"小萝莉";
person.gender = @"女";
person.age = @"18";
可变二进制数据, 用于存person数据
NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];
压缩工具
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
把person压入data中
[archiver encodeObject:person forKey:@"girl"];
结束编码
[archiver finishEncoding];
把data写入文件
NSString *home = NSHomeDirectory();
NSString *filePath = [home stringByAppendingPathComponent:@"data.txt"];
BOOL result = [data writeToFile:filePath atomically:YES];
if (result) {
NSLog(@"写入成功");
} else {
NSLog(@"写入失败");
}
[person release];
[archiver release];
[data release];
}
反归档
- (void)method2 {
NSString *home = NSHomeDirectory();
NSString *filePath = [home stringByAppendingPathComponent:@"data.txt"];
//去文件中读取data
NSData *data = [[NSData alloc] initWithContentsOfFile:filePath];
//解压工具
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person = [unarchiver decodeObjectForKey:@"girl"];
//完成解压
[unarchiver finishDecoding];
NSLog(@"%@", person);
[unarchiver release];
[data release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}