关于 iOS :5种数据持久化问题
简单分享下,希望大牛们多多指点迷津,逐步修改,完善不足支持。借鉴之处,还请谅解
SandBox & NSUserDefaults
1、属性列表 <Plist文件> :XML文件
沙盒机制(SandBox):每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问该沙盒:--Documents:保存应用运行时生成的需要持久化的数据
应用程序包:(Bundle)包含了所有的资源文件和可执行文件
Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积较大、不需要备份的非重要数据
Library/Preference:保存应用的所有偏好设置,iOS的设置应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
#pragma mark 归档文件
- (void)createEditableCopyOfDatabaseIfNeeded{
NSFileManager *fileM=[NSFileManager defaultManager]; //获得沙盒Document里的文件路径
NSString *documentPath=[self applicationDocumentsDirectoryFile]; //创建文件路径
- (NSString *)applicationDocumentsDirectoryFile{ //获得沙盒Document里的文件路径
//获取沙盒Document的路径
NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//添加沙盒路径文件
NSString *path=[docPath stringByAppendingPathComponent:FILE_NAME];
return path; }
2、偏好设置 <Preference> 常用于保存少量数据
选择Resource 中的Settings Bundle,创建。
展开Settings.bundle,其中包含一个Root.plist。Settings程序中的显示项就是从Root.plist中获取的。单击Root.plist以打开它,在空白处单击,选中Show Raw Keys/Values:
创建NSUserDefaults对象之后即可往里面添加数据,它支持的数据类型有NSString、 NSNumber、NSDate、 NSArray、NSDictionary、BOOL、NSInteger、NSFloat等系统定义的数据类型,如果要存放自定义的对象(如自定义的类对象),则必须将其转换成NSData存储:
NSUserDefaults *myData=[NSUserDefaults standardUserDefaults]; //用于存储配置信息 (轻量级本地数据存储)
往NSUserDefaults添加数据后,它们就变成了全局的变量,App中即可读写NSUserDefault中的数据:
一、分开存取: [myData setInteger:X forKey:@”identif”]; //存 X = [myData integerValueForKey:@”identif”]; //取
[setObject: forKey: ] / objectForKey: & [setString: forKey: ] / stringForKey:
二、如果想删除某个数据项,可以使用removeObjectForKey删除数据:
需要注意的是,NSUserDefaults是定时把缓存中的数据写入磁盘的,而不是即时写入,为了防止在写完NSUserDefaults后程序退出导致的数据丢失,可以在写入数据后使用synchronize强制立即将数据写入磁盘:[myData synchronize] 运行上面的语句后,NSUserDefaults中的数据即被写入到.plist文件中
3、对象归档 <NSKeyedArchiver> :
要使用对象归档,对象必须实现NSCoding协议.大部分Object-C对象都符合NSCoding协议,也可以在自定义对象中实现NSCoding协议,要实现NSCoding协议,实现两个方法: - (void) encodeWithCoder:(NSCoder *)aCoder //将属性进行编码的方法
[aCoder encodeObject:_name forKey:@"name"];
- (id)initWithCoder:(NSCoder *)aDecoder //将属性进行解码的方法
name1 = [aDecoder decodeObjectForKey:@"name"];
同时,建议对象也同时实现NSCopying协议,该协议允许复制对象,要实现NSCopying协议须实现 -(id)copyWithZone:(NSZone *)zone 方法
[NSKeyedArchiver archiveRootObject:toFile:] //会首先调用被归档类对象的encodeWithCoder方法对该对象的属性编码,然后再写入文件进行归档
[NSKeyedUnarchiver unarchiveObjectWithFile:path] // 从文件加载数据后,会调用类的initWithCoder方法,实例化该类对象,并恢复属性
4、SQLite3 数据库:
SQLite是一个开源的嵌入式关系数据库,它在2000年由D. Richard Hipp发布,它的减少应用程序管理数据的开销,SQLite可移植性好,很容易使用,很小,高效而且可靠。SQLite嵌入到使用它的应用程序中,它们共用相同的进程空间,而不是单独的一个进程。从外部看,它并不像一个RDBMS,但在进程内部,它却是完整的,自包含的数据库引擎。 嵌入式数据库的一大好处就是在你的程序内部不需要网络配置,也不需要管理。因为客户端和服务器在同一进程空间运行。SQLite 的数据库权限只依赖于文件系统,没有用户帐户的概念。SQLite 有数据库级锁定,没有网络服务器。它需要的内存,其它开销很小,适合用于嵌入式设备。你需要做的仅仅是把它正确的编译到你的程序。
5、Core Data 数据库:
Core Data提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象。
要使用Core Data,需要在Xcode中的数据模型编辑器中设计好各个实体以及定义好他们的属性和关系。之后,通过操作这些对象,结合Core Data完成数据的持久化:@interface ViewController (){
NSManagedObjectContext *_context; //Core Data数据操作的上下文,负责所有数据操作,类似于SQLite数据库的连接句柄 }
@end
//***提示,开发过程中,若对数据模型进行来调整,一定要记住删除沙箱中的数据库连接句柄
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//打开数据库
[self openDB];
//新增数据
[self addPerson];
[self allPersons];
[self updatePerson];
[self removePerson]; }
- (void)openDB{ //打开数据库
/*在沙盒中创建数据库,打开数据库之后,生成一个数据库连接一个句柄db后续数据库操作均基于该句柄
Core Data创建方式:
1、将所有定义好的数据模型文件合并为一个数据模型:NSManagedObjectModel 建立起针对实体对应数据库的SQL语句,以便创建数据表
2、用数据模型来创建持久化存储调度,此时久具备创建表的能力
3、为存储调度添加持久化的数据库(SQLite数据库)若没有新建并创建数据表, 如果存在,直接打开数据库
4、在打开数据库之后,会判断实体当前结构是否一致,若不一致,打开失败 */
//1. 实例化数据模型(将所有定义的模型都加载进来),merge-合并
NSManagedObjectModel *model=[NSManagedObjectModel mergedModelFromBundles:nil];
//2,实例化 持久化存储调度,要建立起桥梁,需要模型
NSPersistentStoreCoordinator *store=[[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:model];
//3,添加一个持久化的数据库到存储调度:建立数据库保存在沙盒URL
NSArray *docs=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path=[docs[0] stringByAppendingPathComponent:@"my.db"];
NSLog(@"%@",path);
NSURL *url=[NSURL fileURLWithPath:path];
//打开或者新建数据库文件
NSError *error=nil;
[store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&error];
if (error){ NSLog(@"its wrong");
}else{ NSLog(@"its right");
_context =[[NSManagedObjectContext alloc]init];
//句柄
_context.persistentStoreCoordinator=store;
}
#pragma mark 查询用户
- (void)allPersons{ //1、实例化一个查询(Fetch)请求
NSFetchRequest *request=[NSFetchRequest fetchRequestWithEntityName:@"Person"]; //条件查询
/*在谓词中contains类似于数据库 like ‘’ 若通过key path查询字段,需要使用%K */
request.predicate=[NSPredicate predicateWithFormat:@"age<30"];
//2、让_context执行查询数据
NSArray *ary=[_context executeFetchRequest:request error:nil];
for (Person *p in ary ) { //遍历
NSLog(@"%@,%@,%@",p.name,p.age,p.height); }
/*实际开发中,通常从表格中选中某行,获取到对应的NSMangedObject,然后进行修改,便可只修改唯一一条记录
常规开发中,应该首先加载所有数据,数据中保存所有记录,这时,在修改个人记录时,是无需再次去查询数据库的 */
- (void)updatePerson{
//1、实例化一个查询(Fetch)请求
NSFetchRequest *request=[NSFetchRequest fetchRequestWithEntityName:@"Person"];
//设置谓词条件
request.predicate=[NSPredicate predicateWithFormat:@"name CONTAINS 'huangyan'"];
//有上下文查询数据
NSArray *result=[_context executeFetchRequest:request error:nil];
for (Person *p in result ) { //遍历
NSLog(@"----%@,%@,%@",p.name,p.age,p.height);
//修改
p.age=@14;
p.name=@"李四"; }
[_context save:nil];