关于数据持久化
数据持久化,字面上的意思来理解,就是将数据存放更长时间。
很显然的,当我们在平时开发中,必然而然的会使用到数据的持久化,但是通用的几种方式,我们应该了然于心。以便于在使用到的时候,能够更好的选择使用哪一种。
通常数据持久化的几种方式
1.NSUserDefaults
2.NSKeyedArchiver(对象模型归档)
3.SQLite
4.Core Data
1.NSUserDefaults
NSUserDefaults是苹果提供的一种偏好设置的方法,将我们需要的一些偏好设置写道plist文件当中。例如,记录主题设置的模式,是否自动登录等等。
NSUserDefaults是苹果提供的一个单例,使用方法很简单,如下:
////write
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@"daytime" forKey:@"themeStyle"];
[defaults synchronize];
////read
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *themeStyle= [defaults objectForKey:@"themeStyle"]
类似于此,NSUserDefaults 还持支NSData,NSString,NSNumber,NSDate,NSArray,NSDictionary这些数据类型。
当然苹果还提供了具体类型的读写方法:
- setBool:forKey:
- setFloat:forKey:
...等
但是,写数据的时候特别注意的是这一句话
[defaults synchronize];
当我们利用NSUserDefaults 来写入数据的时候,系统默认并不是马上就会写道plist里面,但是往往我们需要存一些偏好设置的时候,想法是写进去,plist里面就会马上响应,就可以马上读出来。如果想实现该需求,就需要在我们存储数据的最后面加上synchronize来同步数据到pilst里面。
2.NSKeyedArchiver与沙盒
NSKeyedArchiver 对象归档,就是当我们需要将自定义的类对象进行二进制化归档。而沙盒存储呢,简单的来说,就是将文件给存到本地磁盘中。
NSKeyedArchiver
首先,要使用NSKeyedArchiver归档,就需要实现NSCoding协议。同时实现其序列化和反序列化这两个方法
//反序列化
//从coder中读取数据,保存到相应的变量中
- (id)initWithCoder:(NSCoder *)aDecoder;
// 序列化
//读取实例变量,并把这些数据写到coder中。
-(void)encodeWithCoder:(NSCoder *)coder;
沙盒
关于ios沙盒机制,简单来说就是一个安全权限。默认权限下,苹果只允许IOS应用程序访问程序自己的目录,该目录就称为“沙盒”。
下图是沙河目录
MyApp.app
存放应用程序本身的数据,整个目录是只读的
不会被iTunes同步
Documents
存放应用程序的数据文件(不可再生的)
会被iTunes同步
Documents/Inbox
存放保存由外部应用请求当前应用程序打开的文件
会被同步
Library
苹果建议用来存放默认设置或其它状态信息
会被iTunes同步,但是除了Caches子目录
Library/Caches
主要是缓存文件
不会被iTunes同步
Library/Preferences
应用程序的偏好设置文件。例如NSUserDefaults写的设置数据都会保存到该目录下的一个plist文件中
会被iTunes同步
tmp
各种临时文件,保存应用再次启动时不需要的文件,并且随时有可能被系统清理掉
不会被iTunes同步
简单的使用
了解了NSKeyedArchiver需要什么,沙盒是什么了,下面我们就开始来看代码:
@interface Person: NSObject <NSCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *sex;
@end
//...
//实现序列化和反序列化
@implementation Person
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.name forKey:@"name"];
[aCoder encodeObject:self.sex forKey:@"sex"];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self.name = [aDecoder decodeObjectForKey:@"name"];
self.sex= [aDecoder decodeObjectForKey:@"sex"];
return self;
}
@end
Person* person= [[Person alloc] init];
person.name = @"zhu";
person.age = @"man";
];
//归档,调用encodeWithCoder方法
NSData * perData= [NSKeyedArchiver archivedDataWithRootObject:person];
//读取归档数据,调用initWithCoder
Person* per= [NSKeyedUnarchiver unarchiveObjectWithData:perData];
//也可以将序列化的对象保存到沙盒中
//获得Document的路径
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//拓展名可以自己随便取
NSString *path = [documents stringByAppendingPathComponent:@"person.archiver"];
[NSKeyedArchiver archiveRootObject:person toFile:path];
//读取沙盒中的文件
NSString *documents = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documents stringByAppendingPathComponent:@"person.archiver"];
person *person1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
3.SQLite
SQLite是一个轻量级关系数据库,最初的设计目标是用于嵌入式系统,它占用资源非常少.在iOS中,只需要加入li’blibsqlite3.0依赖以及引入sqlite3.h头文件即可。
关于sqlite在ios中的使用,我并没有深入的了解过,所以这里只是简单的介绍下。
4.Core Data
Core Data是iOS5之后才出现的一个框架,它提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象。
至于到底是用coredata还是sqlite,大家是各持己见,但是我觉得还是应该看具体的业务逻辑。不要局限于某一个工具,而是在合适的时候选择合适的方法就好。
关于coredata我们要知道的几个东西
1.NSManagedObjectContext(托管对象上下文)
负责应用和数据库之间的交互,例如增删查改。
2.NSManagedObjectModel(托管对象模型)
负责coredara里面的模型文件
3.NSPersistentStoreCoordinator(持久化存储协调器)
负责添加持久性数据库,例如sqlite,Binary、XML、或In-Memory等。但要注意这点,Binary和XML格式的存储区是Atomic,意思是就算我们只想修改少量的数据,但是在保存的时候还是得将整个文件都写进磁盘。
对于coredata,初学者不要觉得很神奇,简单的想成是一个对象关系的数据库就行了,不需要写sql语句,就能实现数据的存取。
下面是一些简单的使用:
- (IBAction)addClick:(id)sender {
NSLog(@"addClick");
Employee *em = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:self.ctx];
em.name = @"lisi";
em.height = @172;
em.age = @25;
NSError *error = nil;
[self.ctx save:&error];
if (error) {
NSLog(@"%@===error", error);
} else {
NSLog(@"=====add=success====");
}
}
- (IBAction)readClick:(id)sender {
NSLog(@"readClick");
NSEntityDescription *enty = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:self.ctx];
NSFetchRequest *featch = [[NSFetchRequest alloc] init];
[featch setEntity:enty];
// NSPredicate *pre = [NSPredicate predicateWithFormat:@"name=%@",@"lisi"];
//
// [featch setPredicate:pre];
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:YES];
featch.sortDescriptors = @[sort];
NSArray *arr = [self.ctx executeFetchRequest:featch error:nil];
for (Employee *em in arr) {
NSLog(@"姓名:%@ 身高%@",em.name ,em.height);
}
}
- (IBAction)deleteClick:(id)sender {
NSLog(@"deleteClick");
NSEntityDescription *enty = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:self.ctx];
NSFetchRequest *featch = [[NSFetchRequest alloc] init];
featch.entity = enty;
featch.predicate = [NSPredicate predicateWithFormat:@"name=%@",@"lisi"];
NSArray *arr = [self.ctx executeFetchRequest:featch error:nil ];
for (Employee *em in arr) {
NSLog(@"姓名:%@ 身高%@",em.name ,em.height);
[self.ctx deleteObject:em];
}
[self.ctx save:nil];
}
- (IBAction)updateClick:(id)sender {
NSLog(@"updateClick");
NSEntityDescription *enty = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:self.ctx];
NSFetchRequest *featch = [[NSFetchRequest alloc] init];
featch.entity = enty;
featch.predicate = [NSPredicate predicateWithFormat:@"name=%@",@"lisi"];
NSArray *arr = [self.ctx executeFetchRequest:featch error:nil ];
for (Employee *em in arr) {
NSLog(@"姓名:%@ 身高%@",em.name ,em.height);
em.name = @"wangwu";
}
[self.ctx save:nil];
}
- (NSManagedObjectContext *)ctx
{
if (!_ctx) {
_ctx = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
NSManagedObjectModel *mModel = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mModel];
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *url = [path stringByAppendingPathComponent:@"zhu.sqlite"];
[coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:url] options:nil error:nil];
_ctx.persistentStoreCoordinator = coordinator;
}
return _ctx;
}
结束语
其实关于ios中数据持久化的使用,不会仅限于此,以上只是一些简单的介绍和使用的方法。在当说到数据持久化的时候,我们脑海中应该蹦出一些自己的理解来。自己心中理一个适合自己的知识结构来帮助我们打理逻辑,然后在实际使用场景的时候,根据具体业务来选择具体使用哪一种数据持久化方案。我认为做开发的不要一脑门的死记硬背,一脑门的按照别人的说的来做。看到别人的逻辑的时候,觉得好的,自己心里领会下,觉得不好的,自己在想想怎么去做会更加完美。千万不要做代码的奴隶,而是以一种艺术家,建筑师又或者设计师的角度来审视代码。
网友评论