"IOS数据存储的方式有哪些"
1.plist
2.preference用户偏好设置
3.NSKeyedArchiver(归档)
4.sqlite
5.coredata
"plist文件存储"
应?用沙盒结构分析
应?用程序包:(上图中的Layer)包含了所有的资源?文件和可执?行?文件 Documents:保存应?用运?行时?生成的需要持久化的数据,iTunes同步设备时会
备份该?目录。例如,游戏应?用可将游戏存档保存在该?目录
tmp:保存应?用运?行时所需的临时数据,使?用完毕后再将相应的?文件从该?目录删 除。应?用没有运?行时,系统也可能会清除该?目录下的?文件。iTunes同步设备时 不会备份该?目录
Library/Caches:保存应?用运?行时?生成的需要持久化的数据,iTunes同步设 备时不会备份该?目录。?一般存储体积?大、不需要备份的?非重要数据
Library/Preference:保存应?用的所有偏好设置,iOS的Settings(设置)
应?用会在该?目录中查找应?用的设置信息。iTunes同步设备时会备份该?目录
● 沙盒根??目录:NSString*home=NSHomeDirectory();
● Documents:(2种?方式)
● 利?用沙盒根??目录拼接”Documents”字符串
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];
// 不建议采?用,因为新版本的操作系统可能会修改??目录名
● 利?用NSSearchPathForDirectoriesInDomains函数
// NSUserDomainMask 代表从?用户?文件夹下找
// YES 代表展开路径中的波浪字符“~”
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO);
// 在iOS中,只有?一个??目录跟传?入的参数匹配,所以这个集合?里?面只有?一个元素
NSString *documents = [array objectAtIndex:0];
● tmp:NSString *tmp = NSTemporaryDirectory();
● Library/Caches:(跟Documents类似的2种?方法)
● 利?用沙盒根?目录拼接”Caches”字符串
● 利?用NSSearchPathForDirectoriesInDomains函数(将函数的第2个参数改 为:NSCachesDirectory即可)
● Library/Preference:通过NSUserDefaults类存取该?目录下的设置信息
● 属性列表是?一种XML格式的?文件,拓展名为plist
● 如果对象 是NSString、NSDictionary、NSArray、NSData、NSNumber 等类型,就可以使?用writeToFile:atomically:?方法直接将对象 写到属性列表?文件中
● 将?一个NSDictionary对象归档到?一个plist属性列表中
// 将数据封装成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"?母鸡" forKey:@"name"];
[dict setObject:@"15013141314" forKey:@"phone"];
[dict setObject:@"27" forKey:@"age"];
// 将字典持久化到Documents/stu.plist?文件中
[dict writeToFile:path atomically:YES];
● 成功写?入到Documents?目录下
● ?用?文本编辑器打开,?文件内容为:
读取属性列表,恢复NSDictionary对象
// 读取Documents/stu.plist的内容,实例化NSDictionary
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"name:%@", [dict objectForKey:@"name"]);
NSLog(@"phone:%@", [dict objectForKey:@"phone"]);
NSLog(@"age:%@", [dict objectForKey:@"age"]);
● 打印信息如下
1.字符串 数组 字典 可以直接存储数据在一个文件
2.掌握沙盒备目录的作用以及目录路径获取方式
// Document [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] 持久化数据,比如:文件
// 缓存 [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 微博,另一个设备不会备份
// 临时 NSTemporaryDirectory(); 比如电影。看完之后不看了
// 主目录 NSHomeDirectory();
3.不是所有对象都可以保存到plist文件中,要有实现writeFile方法才可以
4.学会使用SimPholders2打开沙盒目录
ViewController.m
//
// ViewController.m
// A05.plist文件存储
//
// Created by huan on 16/1/22.
// Copyright © 2016年 huanxi. All rights reserved.
//
#import "ViewController.h"
#import "Contact.h"
@interface ViewController ()
@property (nonatomic, copy) NSString *plistPath;
@end
@implementation ViewController
//沙盒路径的方法:(1)前往(2)终端+open+enter(3)第三方框架
//懒加载
-(NSString *)plistPath{
if (!_plistPath) {
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
_plistPath = [doc stringByAppendingPathComponent:@"data.plist"];
}
return _plistPath;
}
- (void)viewDidLoad {
[super viewDidLoad];
// NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// NSLog(@"%@", doc);
//// NSLog(@"%@", NSHomeDirectory());
// NSString *plistPath = [doc stringByAppendingPathComponent:@"data.plist"];
//读取
// NSArray *array = [NSArray arrayWithContentsOfFile:plistPath];
// NSLog(@"%@", array);
//获取缓存路径(cache)
NSString * cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSLog(@"%@", cachePath);
//获取临时路径(tmp)
NSString *tmpPath = NSTemporaryDirectory();
NSLog(@"%@", tmpPath);
//主目录
NSString *homePath = NSHomeDirectory();
NSLog(@"%@", homePath);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// //把数据保存到沙盒的一个plist文件里
//// NSArray *data = @[@"asd", @"asds"];
// NSDictionary *data = @{@"name":@"zhangsan",@"age":@23};
// //获取document目录,用户主目录
// NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// NSLog(@"%@", doc);
//// NSLog(@"%@", NSHomeDirectory());
// NSString *plistPath = [doc stringByAppendingPathComponent:@"data.plist"];
// //把数据写入一个文件
// [data writeToFile:plistPath atomically:YES];
// //读取
// NSArray *array = [NSArray arrayWithContentsOfFile:plistPath];
// NSLog(@"%@", array);
[self testDictionary];
[self testString];
//不是说有对象都可使用writeToFile方法
Contact *contact = [[Contact alloc] init];
contact.name = @"zhangsan";
}
-(void)testString{
NSString *data = @"aabc";
//写字符串
[data writeToFile:self.plistPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
//读字符串
NSString *str = [NSString stringWithContentsOfFile:self.plistPath encoding:NSUTF8StringEncoding error:nil];
NSLog(@"%@", str);
}
-(void)testDictionary{
//把数据保存到沙盒的一个plist文件里
NSDictionary *data = @{@"name":@"zhangsan",@"age":@23};
//把数据写入一个文件
[data writeToFile:_plistPath atomically:YES];
//读取
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:self.plistPath];
NSLog(@"%@", dict);
}
/**
* 测试数组存储在一个plist文件
*/
-(void)testArray{
//把数据保存到沙盒的一个plist文件里
NSArray *data = @[@"asd", @"asds"];
// NSDictionary *data = @{@"name":@"zhangsan",@"age":@23};
//获取document目录,用户主目录
// NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// NSLog(@"%@", doc);
// // NSLog(@"%@", NSHomeDirectory());
// NSString *plistPath = [doc stringByAppendingPathComponent:@"data.plist"];
//把数据写入一个文件
[data writeToFile:_plistPath atomically:YES];
//读取
NSArray *array = [NSArray arrayWithContentsOfFile:self.plistPath];
NSLog(@"%@", array);
}
//查看沙盒路径
//1.控制台打印沙盒的路径,使用finder-前往-文件夹 打开
//2.控制台打印沙盒的路径,打开终端 Open + 路径
//3.使用simholers工具
//4.可以断点 输入po NSHomeDirectory
@end
Contact.h
#import <Foundation/Foundation.h>
@interface Contact : NSObject
@property (nonatomic, copy) NSString *name;
@end
"用户偏好设置"
很多iOS应?用都?支持偏好设置,?比如保存?用户名、密码、字体?大?小等设置,iOS 提供了?一套标准的解决?方案来为应?用加?入偏好设置功能
● 每个应?用都有个NSUserDefaults实例,通过它来存取偏好设置
● ?比如,保存?用户名、字体?大?小、是否?自动登录
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"itcast" forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];
● 读取上次保存的设置
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:@"username"];
float textSize = [defaults floatForKey:@"text_size"];
BOOL autoLogin = [defaults boolForKey:@"auto_login"];
● 注意:UserDefaults设置数据时,不是?立即写?入,?而是根据时间戳定时地把缓存中
的数据写?入本地磁盘。所以调?用了set?方法之后数据有可能还没有写?入磁盘应?用程序
就终?止了。出现以上问题,可以通过调?用synchornize?方法强制写?入
[defaults synchornize];
1.ios中有个NSUserDefaults对象有可保存数据,我们称为用户偏好设置
2.通过[NSUserDefaults standardUserDefaults]可以获取用户偏好设置对象,保存字符串 布尔值 int等数据
3.保存数据时,一定要调用synchronize,因为数据要及时保存到沙盒的文件中
/* NSUserDefaults *defualts = [NSUserDefaults standardUserDefaults];
[defualts setObject:@"zhangsan" forKey:@"username"];
[defualts setObject:@"123" forKey:@"password"];
[defualts setBool:YES forKey:@"autoLogin"];
[defualts setBool:YES forKey:@"rememberPwd"];
//同步
[defualts synchronize];
*/
4.掌握用户偏好设置数据的获取,更改,删除
ViewController.m
//
// ViewController.m
// B02.用户偏好设置
//
// Created by huan on 16/1/22.
// Copyright © 2016年 huanxi. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// [self delete];
[self modify];
}
-(void)modify{
//修改 用户偏好设置 数据
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"321" forKey:@"password"];
[defaults synchronize];
NSLog(@"%@", NSHomeDirectory());
}
-(void)delete{
//删除 用户偏好设置 数据
NSUserDefaults *defautls = [NSUserDefaults standardUserDefaults];
[defautls removeObjectForKey:@"account"];
//删除记得数据也要调用 同步的方法
[defautls synchronize];
NSLog(@"%@", NSHomeDirectory());
}
-(void)read{
//读取 用户偏好设置 数据
NSUserDefaults *defautls = [NSUserDefaults standardUserDefaults];
NSString *account = [defautls objectForKey:@"account"];
NSString *password = [defautls objectForKey:@"password"];
BOOL rememberPwd = [defautls boolForKey:@"rememberPwd"];
BOOL autoLogin = [defautls boolForKey:@"autoLogin"];
NSLog(@"%@, %@, %d, %d", account, password, rememberPwd, autoLogin);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//使用偏好设置保存数据
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//要保存的数据
[defaults setObject:@"zhangsan" forKey:@"account"];
[defaults setObject:@"123" forKey:@"password"];
[defaults setBool:YES forKey:@"autoLogin"];
[defaults setBool:YES forKey:@"rememberPwd"];
//调用同步的方法,把数据保存到沙盒文件
[defaults synchronize];
}
@end
"NSKeyedArchiver归档"
● 如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类 型,可以直接?用NSKeyedArchiver进?行归档和恢复
● 不是所有的对象都可以直接?用这种?方法进?行归档,只有遵守了NSCoding协议 的对象才可以
● NSCoding协议有2个?方法:
● encodeWithCoder:
每次归档对象时,都会调?用这个?方法。?一般在这个?方法?里?面指定如何归档对象中的每 个实例变量,可以使?用encodeObject:forKey:?方法归档实例变量
● initWithCoder: 每次从?文件中恢复(解码)对象时,都会调?用这个?方法。?一般在这个?方法?里?面指定如何解
码?文件中的数据为对象的实例变量,可以使?用decodeObject:forKey?方法解码实例变量
• 归档?一个NSArray对象到Documents/array.archive NSArray *array = [NSArray arrayWithObjects:@”a”,@”b”,nil];
[NSKeyedArchiver archiveRootObject:array toFile:path];
• 归档成功
@interface Person : NSObject<NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) float height;
@end
@implementation Person - (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeInt:self.age forKey:@"age"];
[encoder encodeFloat:self.height forKey:@"height"];
} - (id)initWithCoder:(NSCoder *)decoder {
self.name = [decoder decodeObjectForKey:@"name"];
self.age = [decoder decodeIntForKey:@"age"];
self.height = [decoder decodeFloatForKey:@"height"]; return self;
} - (void)dealloc {
[super dealloc];
[_name release]; }
@end
● 归档(编码)
Person *person = [[[Person alloc] init] autorelease];
person.name = @"MJ";
person.age = 27;
person.height = 1.83f;
[NSKeyedArchiver archiveRootObject:person toFile:path];
● 恢复(解码)
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
● 如果?父类也遵守了NSCoding协议,请注意:
● 应该在encodeWithCoder:?方法中加上?一句
[super encodeWithCode:encode];
确保继承的实例变量也能被编码,即也能被归档
● 应该在initWithCoder:?方法中加上?一句
self = [super initWithCoder:decoder];
确保继承的实例变量也能被解码,即也能被恢复
NSData
● 使?用archiveRootObject:toFile:?方法可以将?一个对象直接写?入到
?一个?文件中,但有时候可能想将多个对象写?入到同?一个?文件中,那么就
要使?用NSData来进?行归档对象
● NSData可以为?一些数据提供临时存储空间,以便随后写?入?文件,或者存
放从磁盘读取的?文件内容。可以使?用[NSMutableData data]创建可
变数据空间
NSData-归档2个Person对象到同?一?文件中
● 归档(编码)
// 新建?一块可变数据区
NSMutableData *data = [NSMutableData data];
// 将数据区连接到?一个NSKeyedArchiver对象
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
// 开始存档对象,存档的数据都会存储到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存档完毕(?一定要调?用这个?方法)
[archiver finishEncoding];
// 将存档的数据写?入?文件
[data writeToFile:path atomically:YES];
NSData-从同?一?文件中恢复2个Person对象
● 恢复(解码)
// 从?文件中读取数据
NSData *data = [NSData dataWithContentsOfFile:path];
// 根据数据,解析成?一个NSKeyedUnarchiver对象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person1 = [unarchiver decodeObjectForKey:@"person1"];
Person *person2 = [unarchiver decodeObjectForKey:@"person2"]; // 恢复完毕
[unarchiver finishDecoding];
利用归档实现深复制
/*什么叫归档 归档就是把数据保存到一个文件中*/
1.使用NSKeyedArchiver可以将NSArray NSDictiony NSString等对象归档到一个文件
2.只有实现了NSCoding协议的对象才可使用NSKeyedArchiver进行归档
3.将模型对象保存到一个文件时,对象要遵守NSCoding协议,并实现NSKeyedArchiver的encodeWithCoder方法,
4.从归档文件里读取对象时要实现NSCoding的initWithCoder方法
5.ios中,控制器,控件都继承NSCoding,storyboard/xib都是使用NSKeyedArchiver进行归档的
ViewController.m
//
// ViewController.m
// B03.NSCoding
//
// Created by huan on 16/1/22.
// Copyright © 2016年 huanxi. All rights reserved.
//
#import "ViewController.h"
#import "Contact.h"
@interface ViewController ()
/**
* NSKeyedArchiver 保存数据
* NSKeyedUnarchiver 读取数据
*/
@property (nonatomic, copy) NSString *plistPath;
-(IBAction)saveData;
-(IBAction)readData;
@end
@implementation ViewController
-(NSString *)plistPath{
if (!_plistPath) {
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
_plistPath = [doc stringByAppendingPathComponent:@"data.plist"];
}
return _plistPath;
}
//-(id)initWithCoder:(NSCoder *)aDecoder{
// if (self = [super init]) {
//
// }
// return self;
//}
- (void)viewDidLoad {
[super viewDidLoad];
//保存字典
[self testDict];
//读字典
NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithFile:self.plistPath];
NSLog(@"%@", dict);
}
-(IBAction)saveData{
//使用 “归档” 方法保存数据
// NSArray *data = @[@"abc", @23];
// NSDictionary *data = @{@"name":@"zhangs", @"height":@90};
//
// //直接把一个对象保存到沙盒里
// [NSKeyedArchiver archiveRootObject:data toFile:self.plistPath];
// NSLog(@"%@", NSHomeDirectory());
Contact *contact = [[Contact alloc] init];
contact.name = @"张三";
contact.age = 27;
contact.tel = @"13512312345";
[NSKeyedArchiver archiveRootObject:contact toFile:self.plistPath];
NSLog(@"%@", NSHomeDirectory());
}
-(IBAction)readData{
//读数据
Contact *contact = [NSKeyedUnarchiver unarchiveObjectWithFile:self.plistPath];
NSLog(@"%@ %d %@",contact.name, contact.age, contact.tel);
}
/**
* 测试 系统的NSDictionary NSArray的归档
* 只有 对象 遵守了NSCoding协议才可以使用NSKeyedArchiver进行数据存储
*/
-(void)testDict{
//使用 “归档” 方法保存数据
NSDictionary *data = @{@"name":@"zhangs", @"height":@90};
//直接把一个对象保存到沙盒里
[NSKeyedArchiver archiveRootObject:data toFile:self.plistPath];
NSLog(@"%@", NSHomeDirectory());
}
@end
Contact.h
#import <Foundation/Foundation.h>
#import "Person.h"
@interface Contact : Person
@property (nonatomic, copy) NSString *tel;//当有属性是必须实现NSCondig的两种方法。
@end
Contact.m
#import "Contact.h"
@implementation Contact
-(void)encodeWithCoder:(NSCoder *)aCoder{
[super encodeWithCoder:aCoder];
//添加自己属性的存储
[aCoder encodeObject:self.tel forKey:@"tel"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
//子类实现initWithCoder方法时,self 不要写 self = [super init];
self.tel = [aDecoder decodeObjectForKey:@"tel"];
}
return self;
}
@end
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
Person.m
#import "Person.h"
@implementation Person
-(void)encodeWithCoder:(NSCoder *)aCoder{
//指定 每个属性 怎么存储
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeInt:self.age forKey:@"age"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
//读取 数据 设置每个属性
if (self = [super init]) {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.age = [aDecoder decodeIntForKey:@"age"];
}
return self;
}
@end
原文:http://www.cnblogs.com/Lu2015-10-03/p/5164712.html