简介
在iOS开发中,基于网络数据的本地存储是提高App客户端操作的用户友好度和提高App的运行流畅度。本文对常用的一些存储方式做了整理,具体常见方式有如下几种:
- NSUserDefaults
- NSKeyedArchiver
- Plist操作
- 沙盒存储
- CoreData
- 第三方存储框架
NSUserDefaults
一般对于一些基本的用户设置,因为数据量很小,我们可以使用OC语言中的 NSUserDefaults类来进行处理。使用方法很简单,只需要调用类中的方法即可。
NSUserDefaults支持的数据类型有:NSNumber(NSInteger、float、double),NSString,NSDate,NSArray,NSDictionary,BOOL.
数组的存取:
NSMutableArray *mutableArray = [[NSMutableArray alloc]initWithObjects:@"1", nil];
//NSUserDefaults只能存储不可变对象
NSArray * array = [NSArray arrayWithArray:mutableArray];
//存入数组并同步
[[NSUserDefaults standardUserDefaults] setObject:array forKey:@"mutableArr"];
[[NSUserDefaults standardUserDefaults] synchronize];
//读取存入的数组 打印,取出数据赋值给可变数组
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:[user objectForKey:@"mutableArr"]];
NSLog(@"%@",arr);
注意:对相同的Key赋值约等于一次覆盖,要保证每一个Key的唯一性。
字符串的存取:
//将NSString 对象存储到 NSUserDefaults 中
NSString *passWord = @"1234567";
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
[user setObject:passWord forKey:@"userPassWord"];
图片的存取:
//存储
UIImage *image =[UIImage imageNamed:@"somename"];
NSData *imageData = UIImageJPEGRepresentation(image, 100);//把image归档为NSData
[defaults setObject:imageData forKey:@"image"];
[defaults synchronize];
//读取
NSData *imageData = [defaults dataForKey:@"image"];
UIImage *image = [UIImage imageWithData:imageData];
NSUserDefaults提供了若干简便方法可以存储某些常用类型的值,例如:
- setBool:forKey:
- setFloat:forKey:
- setInteger:forKey:
- setDouble:forKey:
- setURL:forKey:
NSKeyedArchiver
采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议,并且该对象对应的类必须提供encodeWithCoder:和initWithCoder:方法。前一个方法告诉系统怎么对对象进行编码,而后一个方法则是告诉系统怎么对对象进行解码。
归档操作:
如果对Possession对象allPossession归档保存,只需要NSCoder子类NSKeyedArchiver的方法archiveRootObject:toFile: 即可。
NSString *path = [self possessionArchivePath];
[NSKeyedArchiver archiveRootObject:allPossessions toFile: path ]
解档操作:
同样调用NSCoder子类NSKeyedArchiver的方法unarchiveRootObject:toFile: 即可
allPossessions = [[NSKeyedUnarchiver unarchiveObjectWithFile:path] retain];
Plist属性列表
plist,全名PropertyList,即属性列表文件,它是一种用来存储串行化后的对象的文件。这种文件,在ios开发过程中经常被用到。这种属性列表文件的扩展名为.plist,因此通常被叫做plist文件。文件是xml格式的。Plist文件是以key-value的形式来存储数据。既可以用来存储用户设置,也可以用来存储一些需要经常用到而不经常改动的信息。
创建
可以通过新建一个.plist的文件创建plist属性列表,创建的字段类型有Array, Dictionary,Boolean, Data, String, Date, Number等。
通过代码创建Plist:
NSFileManager *fm = [NSFileManager defaultManager];
//找到Documents文件所在的路径
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUSErDomainMask, YES);
//取得第一个Documents文件夹的路径
NSString *filePath = [path objectAtIndex:0];
//把TestPlist文件加入
NSString *plistPath = [filePath stringByAppendingPathComponent:@"test.plist"];
//开始创建文件
[fm createFileAtPath:plistPath contents:nil attributes:nil];
删除
[fm removeItemAtPath:plistPath error:nil];
写入
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"zhangsan",@"1",@"lisi",@"2", nil];
//把数据写入plist文件
[dic writeToFile:plistPath atomically:YES];
读取
NSDictionary *dic2 = [NSDictionary dictionaryWithContentsOfFile:plistPath];
//打印数据
NSLog(@"key1 is %@",[dic2 valueForKey:@"1"]);
沙盒存储
沙盒是系统为了ios程序分配的可以读写数据的文件区域。沙盒中有三个重要的文件夹:
1. Documents:用于存储NSUesrDefults之外的数据。
获取方式:
// 获得应用程序沙盒的Documents文件夹路径
NSArray *arrDocumentPaths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentPath=[arrDocumentPaths objectAtIndex:0];
NSLog(@"Documents path: %@",documentPath);
2. Tmp用于存储临时数据,当数据不再需要的时候我们将删除数据。
// 获得应用程序沙盒的tmp文件夹路径
NSString *TmpPath= NSTemporaryDirectory();
3. Library:NSUserDefults的数据保存在LIbrary/Preferences下面。
// 获得应用程序沙盒的Caches文件夹路径
NSArray *arrCachesPaths = NSSearchPathForDirectoriesInDomains (NSCachesDirectory,NSUserDomainMask,YES);
NSString *CachesPath=[arrCachesPaths objectAtIndex:0];
NSLog(@"Caches path: %@",CachesPath);
// 获得应用程序沙盒的Downloads文件夹路径
NSArray *arrDownloadPaths = NSSearchPathForDirectoriesInDomains (NSDownloadsDirectory,NSUserDomainMask,YES);
NSString *loadPathsPath=[arrDownloadPaths objectAtIndex:0];
NSLog(@"Downloads path: %@",loadPathsPath);
CoreData
CoreData是iOS SDK里的一个很强大的框架,允许程序员以面向对象的方式储存和管理数据。使用CoreData框架,程序员可以很轻松有效地通过面向对象的接口管理数据。
CoreData框架提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite3数据库文件中,也能够将保存在数据库中的数据还原成OC对象。
增加
- (void)insertData {
NSEntityDescription*entity = [NSEntityDescriptionentityForName: @"Person"inManagedObjectContext: self.manageObjectContext];
Person*person = [[Personalloc]initWithEntity: entityinsertIntoManagedObjectContext:self.manageObjectContext];
person.name=@"钢铁侠";
person.age=@40;
person.height=@180;
__autoreleasing NSError *error;
[self.manageObjectContextsave:&error];
if(error) {
NSLog(@"数据添加失败");
}else{
NSLog(@"数据添加成功");
}
}
更新数据
- (void)updateData{
//修改数据
self.selectedPerson.name=@"Mark47";
self.selectedPerson.age=@1;
__autoreleasingNSError*error;
//保存数据
[self.manageObjectContextsave:&error];
if(error) {
NSLog(@"数据更新失败");
}else{
NSLog(@"数据更新成功");
}
}
删除数据
- (void) deleteData{
[self.manageObjectContextdeleteObject:self.selectedPerson];
__autoreleasingNSError*error;
[self.manageObjectContextsave:&error];
if(error) {
NSLog(@"数据删除失败");
}else{
NSLog(@"数据删除成功");
}
}
第三方存储框架
FMDB
FMDB是第三方的SQLite数据库,以Objective-C的方式封装了SQLite的C语言API,使用起来更加的方便,对多线程的并发进行处理,所以是线程安全的,轻量级框架,使用灵活。
使用FMDataBase类建立数据库
//1.获得数据库文件的路径
NSString *doc =[NSSearchPathForDirectoriesInDomains (NSDocumentDirectory,NSUserDomainMask, YES) lastObject];
NSString *fileName = [doc stringByAppendingPathComponent: @“student.sqlite”];
//2.获得数据库
FMDatabase *db = [FMDatabase databaseWithPath:fileName];
//3.使用如下语句,如果打开失败,可能是权限不足或者资源不足。通常打开完操作操作后,需要调用 close 方法来关闭数据库。在和数据库交互 之前,数据库必须是打开的。如果资源或权限不足无法打开或创建数据库,都会导致打开失败。
if ([db open]){
//4.创表
BOOL result = [db executeUpdate:@“CREATE TABLE IF NOT EXISTS t_student (id integer PRIMARY KEY AUTOINCREM ENT, name text NOT NULL, age integer NOT NULL);”];
if (result){
NSLog(@“创建表成功”);
}
}
向数据库中增加数据:executeUpdate:
if ([db open]) {
NSString *insertSql1= [NSString stringWithFormat:@"INSERT INTO '%@' ('%@', '%@', '%@') VALUES ('%@', '%@', '%@')",TABLENAME, NAME, AGE, ADDRESS, @"张三", @"13", @"济南"];
BOOL res = [db executeUpdate:insertSql1];
NSString *insertSql2 = [NSString stringWithFormat:@"INSERT INTO '%@' ('%@', '%@', '%@') VALUES ('%@', '%@', '%@')",TABLENAME, NAME, AGE, ADDRESS, @"李四", @"12", @"济南"];
BOOL res2 = [db executeUpdate:insertSql2];
if (!res) {
NSLog(@"error when insert db table");
} else {
NSLog(@"success to insert db table");
}
[db close];
}
数据库删除数据操作:executeUpdate:
if ([db open]) {
NSString *deleteSql = [NSString stringWithFormat:
@"delete from %@ where %@ = '%@'",
TABLENAME, NAME, @"张三"];
BOOL res = [db executeUpdate:deleteSql];
if (!res) {
NSLog(@"error when delete db table");
} else {
NSLog(@"success to delete db table");
}
[db close];
}
数据库修改数据操作:executeUpdate:
if ([db open]) {
NSString *updateSql = [NSString stringWithFormat:@"UPDATE '%@' SET '%@' = '%@' WHERE '%@' = '%@'", TABLENAME, AGE, @"15" ,AGE, @"13"];
BOOL res = [db executeUpdate:updateSql];
if (!res) {
NSLog(@"error when update db table");
} else {
NSLog(@"success to update db table");
}
[db close];
}
数据库查询数据操作:executeQuery:
if ([db open]) {
NSString * sql = [NSString stringWithFormat:
@"SELECT * FROM %@",TABLENAME];
FMResultSet * rs = [db executeQuery:sql];
while ([rs next]) {
int Id = [rs intForColumn:ID];
NSString * name = [rs stringForColumn:NAME];
NSString * age = [rs stringForColumn:AGE];
NSString * address = [rs stringForColumn:ADDRESS];
NSLog(@"id = %d, name = %@, age = %@ address = %@", Id, name, age, address);
}
[db close];
}
FMDB中的多线程操作:
//1.创建队列
FMDatabaseQueue *queue = [FMDatabaseQueue
databaseQueueWithPath:aPath];
__block BOOL whoopsSomethingWrongHappened = true;
//2.把任务包装到事务里
[queue inTransaction:^(FMDatabase *db, BOOL *rollback)
{
whoopsSomethingWrongHappened &= [db executeUpdate:@“INSERT INTO myTable VALUES (?)”, [NSNumber numberWith:1]];
whoopsSomethingWrongHappened &= [db
executeUpdata:@“INSERT INTO myTable VALUES (?)”,
[NSNumber numberWithInt:2]];
whoopsSomethingWrongHappened &= [db
executeUpdata:@“INSERT INTO myTable VALUES (?)”[NSNumber
numberWithInt:3]];
//如果有错误 返回
if (!whoopsSomethingWrongHappened)
{
*rollback = YES;
return;
}
}];