[关闭]
@qidiandasheng 2016-09-05T12:07:53.000000Z 字数 6484 阅读 2199

iOS里的数据持久化

iOS理论


前言

所谓数据持久化,就是数据的存储。在iOS里数据的存储有以下几种:

沙盒

在说数据存储之前肯定绕不开苹果的沙盒机制。出于安全考虑,iOS系统的沙盒机制规定每个应用都只能访问当前沙盒目录下面的文件(也有例外,比如系统通讯录能在用户授权的情况下被第三方应用访问)。

Xcode7上模拟器的沙盒路径:

数据目录:

/Users/用户名/Library/Developer/CoreSimulator/Devices/模拟器UDID/data/Containers/Data/Application/对应应用程序文件夹

这里面主要有Documents、Library(Caches和Preferences)、tmp,如图:

.app目录:

/Users/用户名/Library/Developer/CoreSimulator/Devices/模拟器UDID/data/Containers/Bundle/Application/对应应用程序文件夹/应用名.app

获取沙盒目录:

  1. NSLog(@"%@",NSHomeDirectory());
  2. 输出:/var/mobile/Applications/21A34B34-9B30-4B8A-854E-1553480C078F

.app

  1. NSLog(@"%@",[[NSBundle mainBundle] bundlePath]);
  2. 输出:/var/mobile/Containers/Data/Applications/21A34B34-9B30-4B8A-854E-1553480C078F/PhoneCall.app

Documents

  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  2. NSString *path = [paths objectAtIndex:0];
  3. NSLog(@"%@",path);
  4. 输出:/var/mobile/Containers/Data/Applications/21A34B34-9B30-4B8A-854E-1553480C078F/Documents

Library

  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
  2. NSString *path = [paths objectAtIndex:0];
  3. NSLog(@"%@", path);
  4. 输出:/var/mobile/Containers/Data/Application/21A34B34-9B30-4B8A-854E-1553480C078F/Library

Library/Caches

  1. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  2. NSString *path = [paths objectAtIndex:0];
  3. NSLog(@"%@", path);
  4. 输出:/var/mobile/Containers/Data/Application/21A34B34-9B30-4B8A-854E-1553480C078F/Library/Caches

Library/Preferences

tmp

  1. NSLog(@"%@",NSTemporaryDirectory());
  2. 输出:/private/var/mobile/Containers/Data/Applications/21A34B34-9B30-4B8A-854E-1553480C078F/tmp/

plist文件(Documents目录)

plist,全名PropertyList,即属性列表文件,它是一种用来存储串行化后的对象的文件。这种文件,在ios开发过程中经常被用到。这种属性列表文件的扩展名为.plist,因此通常被叫做plist文件。文件是xml格式的。Plist文件是以key-value的形式来存储数据。既可以用来存储用户设置,也可以用来存储一些需要经常用到而不经常改动的信息。

可以被序列化的类型只有如下几种:

  1. NSArray;
  2. NSMutableArray;
  3. NSDictionary;
  4. NSMutableDictionary;
  5. NSData;
  6. NSMutableData;
  7. NSString;
  8. NSMutableString;
  9. NSNumber;
  10. NSDate;

获得文件路径:

我们看到一般plist文件都是存储在沙盒的Documents目录下的。如果document里没有此文件,会自动创建,读取赋值后,便可使用。

  1. NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
  2. NSString *fileName = [path stringByAppendingPathComponent:@"userName.plist"];

存储

  1. NSArray *array = @[@"齐滇大圣", @"哈哈", @"呵呵"];
  2. [array writeToFile:fileName atomically:YES];

读取

  1. NSArray *result = [NSArray arrayWithContentsOfFile:fileName];
  2. NSLog(@"%@", result);

删除plist文件

  1. NSFileManager *fileManage = [NSFileManager defaultManager];
  2. NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:@"userName.plist"];
  3. //如果文件路径存在的话
  4. BOOL isExist = [fileManage fileExistsAtPath:filePath];
  5. if (isExist) {
  6. NSError *err;
  7. [fileManage removeItemAtPath:filePath error:&err];
  8. }

preference(Library/preferences目录)

偏好设置主要用来存储一些存储轻量级的本地数据,比如一些应用程序的配置信息,用户名、密码之类的。

偏好设置会将所有数据保存到同一个文件中。即preference目录下的一个以此应用包名来命名的plist文件。

使用

  1. //获得NSUserDefaults文件
  2. NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  3. //向文件中写入内容
  4. [userDefaults setObject:@"齐滇大圣" forKey:@"name"];
  5. [userDefaults setBool:YES forKey:@"sex"];
  6. [userDefaults setInteger:21 forKey:@"age"];
  7. //立即同步,如果没有调用synchronize方法,系统会根据I/O情况不定时刻地保存到文件中。所以如果需要立即写入文件的就必须调用synchronize方法。
  8. [userDefaults synchronize];
  9. //读取文件
  10. NSString *name = [userDefaults objectForKey:@"name"];
  11. BOOL sex = [userDefaults boolForKey:@"sex"];
  12. NSInteger age = [userDefaults integerForKey:@"age"];
  13. NSLog(@"%@, %d, %ld", name, sex, age);

DSCategories里的NSUserDefaults+SafeAccess分类可以快速方便的操作NSUserDefaults

NSKeyedArchiver(Doucuments目录)

归档在iOS中是另一种形式的序列化,只要遵循了NSCoding协议的对象都可以通过它实现序列化。NSStringNSDictionaryNSArrayNSDataNSNumber等类型都遵循了NSCoding协议。

NSCoding协议有2个方法:

归档一个NSArray对象

  1. NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"array.archive"];
  2. NSArray *array = [NSArray arrayWithObjects:@”哈哈”,@”呵呵”,nil];
  3. [NSKeyedArchiver archiveRootObject:array toFile:filePath];
  4. //恢复NSArray对象
  5. NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

归档Person对象

  1. @interface Person : NSObject<NSCoding>
  2. @property (nonatomic, copy) NSString *name;
  3. @property (nonatomic, assign) int age;
  4. @property (nonatomic, assign) float height;
  5. @end
  1. @implementation Person
  2. - (void)encodeWithCoder:(NSCoder *)encoder {
  3. [encoder encodeObject:self.name forKey:@"name"];
  4. [encoder encodeInt:self.age forKey:@"age"];
  5. [encoder encodeFloat:self.height forKey:@"height"];
  6. }
  7. - (id)initWithCoder:(NSCoder *)decoder {
  8. self.name = [decoder decodeObjectForKey:@"name"];
  9. self.age = [decoder decodeIntForKey:@"age"];
  10. self.height = [decoder decodeFloatForKey:@"height"];
  11. return self;
  12. }
  13. @end
  1. NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.archive"];
  2. Person *person = [[Person alloc] init];
  3. person.name = @"hosea";
  4. person.age = 22;
  5. person.height = 1.83f;
  6. [NSKeyedArchiver archiveRootObject:person toFile:filePath];
  1. Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

注意

如果父类也遵守了NSCoding协议,请注意:

  1. 应该在encodeWithCoder:方法中加上一句
  2. [super encodeWithCode:encode];
  3. 确保继承的实例变量也能被编码,即也能被归档
  4. 应该在initWithCoder:方法中加上一句
  5. self = [super initWithCoder:decoder];
  6. 确保继承的实例变量也能被解码,即也能被恢复

SQLite3(Doucuments目录)

SQLite3是一款开源的嵌入式关系型数据库,可移植性好、易使用、内存开销小。
SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中。

一般我们创建的的数据库是生成在Doucuments目录下以dataName.sqlite命名的。

iOS中原生的SQLite API在使用上相当不友好,于是我们一般都会使用将SQLite API进行过封装的第三方库。比如FMDB

Core Data

Core Data 是 iOS3.0 时引入的一个数据持久化的框架。他与 sqlite 对比最大的优点莫过于支持对象的存储了,苹果的官方文档说其简化了数据库的操作,使用 CoreData 确实可以大量减少代码中的 SQL 语句。

其实 Core Data 是构建在 SQLite 之上,对数据存储层进行了进一步的抽象。虽然说Core Data减少了SQL语句,但是其学习成本并没有降低,复杂度依旧挺高,而且性能也没特别好。

详情可以阅读唐巧的我为什么不喜欢 Core Data这篇文章。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注