iOS开发之数据持久化存储

概论

数据持久化存储:所谓持久化存储就是将数据保存到硬盘中,使得应用程序或者机器在重启后可以访问之前保存的数据。

常见方式:

  • plist文件(属性列表)
  • preference(偏好设置)
  • NSKeyedArchiver(归档)
  • SQLite3(数据库)
  • 发送网络请求(保存在服务器上)
  • CoreData(苹果基于数据库封装的持久化存储工具,这种方式效率不高,因为会帮我们动态生成很多重复的代码,我只有写XMPP的时候会用一下,因为XMPP里面的存储用的就是CoreData)

沙盒

说到持久化存储就不得不说一下苹果的沙盒机制,苹果的一个应用程序就对应一个沙盒。

这样做的好处有以下几点:

  1. 每个应用程序都有自己的存储空间
  2. 应用程序不能翻过自己的围墙去访问别的存储空间的内容
  3. 应用程序请求的数据都要通过权限检测,假如不符合条件的话,不会被放行。

那怎么打开沙盒呢?

  1. 可以在应用程序中打一个断点,然后在输出框((lldb)后面)中输入命令po NSHomeDirectory();你就能看到对应的路径,在spotlight中搜索对应的路径就能找到对应的沙盒了。或者直接NSLog(@"%@",NSHomeDirectory())也可以得到路径;
  2. 这种方法更方便,在Finder上点->前往->前往文件夹,输入/Users/username/Library/Application Support/iPhone Simulator/  前往。username这里写你的用户名。

进入沙盒之后我们能看到三个文件夹:

  • Documents:苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录
  • Library:存储程序的默认设置或其它状态信息

    *Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除

    *Preferences:偏好设置是专门用来保存应用程序的配置信息的,一般不要在偏好设置中保存其他数据。

  • tmp:提供一个即时创建临时文件的地方。

    iTunes在与iPhone同步时,备份所有的Documents和Library文件。

    iPhone在重启时,会丢弃所有的tmp文件。


那我们怎么在程序中得到这些路径呢?

Document:

NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"%@", documentPath);

Library/Caches:

NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"%@", cachePath);

tmp:

NSString *tmpPath = NSTemporaryDirectory();
NSLog(@"%@", tmpPath);

plist文件

plist就是将某些特定的类,通过XML方式保存在目录中。

可以被序列化的类型只有以下几种:(其中根结点必须是NSArray或者NSDictionary)

NSArray;
NSMutableArray;
NSDictionary;
NSMutableDictionary;
NSData;
NSMutableData;
NSString;
NSMutableString;
NSNumber;
NSDate;
BOOL
    //获取文件路径
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    NSString *fileName = [documentPath stringByAppendingPathComponent:@"file.plist"];
    //存储
    NSArray *array = @[@{@"字典":@"dict"},
                       @YES,
                       @"string",
                       @(10),
                       ];
    [array writeToFile:fileName atomically:YES];
    //读取
    NSArray *resultArray = [NSArray arrayWithContentsOfFile:fileName];
    NSLog(@"%@",resultArray);

 

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

//1.获得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中写入内容
[userDefaults setObject:@"wuhongxing" forKey:@"name"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger:21 forKey:@"age"];
//2.1立即同步
[userDefaults synchronize];
//3.读取文件
NSString *name = [userDefaults objectForKey:@"name"];
BOOL sex = [userDefaults boolForKey:@"sex"];
NSInteger age = [userDefaults integerForKey:@"age"];
NSLog(@"%@, %d, %ld", name, sex, age);

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

1.遵循NSCoding协议

@interface Person : NSObject <NSCoding>
/**名字*/
@property (nonatomic, copy) NSString *name;
/**年龄*/
@property (nonatomic, assign) NSInteger age;
/**头像*/
@property (nonatomic, strong) UIImage *avatar;

@end

2.实现NSCoding协议

//归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:_avatar forKey:@"avatar"];
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
}
//解档
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];
    }
    return self;
}

特别注意:如果归档的类是某个自定义类的子类,就需要在归档和解档之前先实现父类的归档和解档方法。即 [super encodeWithCoder:aCoder] 和 [super initWithCoder:aDecoder] 方法;

3.使用

    //需要把对象归档是调用NSKeyedArchiver的工厂方法 archiveRootObject: toFile: 方法。
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
    Person *per = [[Person alloc] init];
    per.name = @"whx";
    per.age = 24;
    per.avatar = UIImagePNGRepresentation([UIImage imageNamed:@"tab_accountH"]);
    [NSKeyedArchiver archiveRootObject:per toFile:documentPath];
    
    //需要从文件中解档对象就调用NSKeyedUnarchiver的一个工厂方法 unarchiveObjectWithFile: 即可。
    Person *resultPer = [NSKeyedUnarchiver unarchiveObjectWithFile:documentPath];
    if (resultPer) {
        NSLog(@"%@ %li %@",resultPer.name,resultPer.age,[UIImage imageWithData:per.avatar]);
    }

SQLite3:之前的所有存储方法,都是覆盖存储。如果想要增加一条数据就必须把整个文件读出来,然后修改数据后再把整个内容覆盖写入文件。所以它们都不适合存储大量的内容。

1.字段类型

表面上SQLite将数据分为以下几种类型:

  • integer : 整数

  • real : 实数(浮点数)

  • text : 文本字符串

  • blob : 二进制数据,比如文件,图片之类的

  • varchar : 字符串类型

实际上SQLite是无类型的。即不管你在创表时指定的字段类型是什么,存储是依然可以存储任意类型的数据。而且在创表时也可以不指定字段类型。SQLite之所以什么类型就是为了良好的编程规范和方便开发人员交流,所以平时在使用时最好设置正确的字段类型!主键必须设置成integer

2. 准备工作

准备工作就是导入依赖库啦,在iOS中要使用SQLite3,需要添加库文件:libsqlite3.dylib并导入主头文件,这是一个C语言的库,所以直接使用SQLite3还是比较麻烦的。

3.如何使用:数据库涉及到的常见操作有增、删、改、查。

基于FMDB的再封装

1.简介

FMDB是iOS平台的SQLite数据库框架,它是以OC的方式封装了SQLite的C语言API,它相对于cocoa自带的C语言框架有如下的优点:

使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码

对比苹果自带的Core Data框架,更加轻量级和灵活

提供了多线程安全的数据库操作方法,有效地防止数据混乱

2.核心类

FMDB有三个主要的类:

  • FMDatabase

一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句

  • FMResultSet

使用FMDatabase执行查询后的结果集

  • FMDatabaseQueue

用于在多线程中执行多个查询或更新,它是线程安全的

3.使用:等我写关于数据库的时候详细说。

 

你可能感兴趣的:(iOS开发之数据持久化存储)