码迷,mamicode.com
首页 > 移动开发 > 详细

iOS开发之数据持久化存储

时间:2015-11-23 18:15:59      阅读:160      评论:0      收藏:0      [点我收藏+]

标签:

概论

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

常见方式:

  • 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.使用:基于FMDB的二次迭代,更加面向对象(先要定义两个全局变量,数据库FMDatabase *_database和NSLock *_lock(为了线程安全,防止两个线程同时修改数据库里的数据))

打开数据库

/**
 *  构造方法
 *
 *  @param path 数据库路径
 */
- (instancetype)initWithDataBasePath:(NSString *)path
{
    if (self = [super init]) {
        _database = [[FMDatabase alloc] initWithPath:path];
        //创建线程锁
        _lock = [[NSLock alloc] init];
        BOOL ret = [_database open];
        PERROR(ret, "open");
    }
    return self;
}

创建表单

- (void)createTable:(NSString *)tableName primaryKey:(NSString *)keyName primaryType:(NSString *)colType otherColums:(NSDictionary *)colums
{
    [_lock lock];   //加锁
    NSMutableString * sql = [NSMutableString stringWithFormat:@"CREATE TABLE IF NOT EXISTS %@(%@ %@ PRIMARY KEY", tableName, keyName, colType];
    for (NSString * key in colums) {
        //key是列名
        [sql appendFormat:@", %@ %@", key, colums[key]];
    }
    [sql appendString:@");"];
    //FMDB会自动添加分号
    
    BOOL ret = [_database executeUpdate:sql];
    PERROR(ret, "create table");
    [_lock unlock]; //解锁
}

删除表单

/**
 *  删除表单
 *
 *  @param tableName 表单名
 */
- (void)dropTable:(NSString *)tableName
{
    [_lock lock];
    NSString * sql = [NSString stringWithFormat:@"DROP TABLE %@;", tableName];
    BOOL ret = [_database executeUpdate:sql];
    PERROR(ret, "drop table");
    [_lock unlock];
}

插入数据

/**
 *  插入数据
 *
 *  @param tableName 表单名
 *  @param dict      key:列名 value:列值
 */
- (void)insertRecordIntoTable:(NSString *)tableName withColumsAndValues:(NSDictionary *)dict;
{
    [_lock lock];
    //拼接列名
    NSMutableString * colStr = [NSMutableString string];
    //拼接value
    NSMutableString * valuesStr = [NSMutableString string];
    
    colStr.string = [dict.allKeys componentsJoinedByString:@","];
    NSMutableArray * xArray = [NSMutableArray array];
    for (NSUInteger i = 0; i < dict.count; i++) {
        [xArray addObject:@"?"];
    }
    valuesStr.string = [xArray componentsJoinedByString:@","];
    
    //创建SQL
    NSMutableString * sql = [NSMutableString stringWithFormat:@"INSERT INTO %@(%@) VALUES(%@);", tableName, colStr, valuesStr];
    
    BOOL ret = [_database executeUpdate:sql withArgumentsInArray:dict.allValues];
    PERROR(ret, "insert record");
    [_lock unlock];
}

拼接筛选的字符串

- (NSString *)whereStringFromWhereDictionary:(NSDictionary *)dict
{
    //拼接删选的字符串
    NSMutableArray * whereArray = [NSMutableArray array];
    for (NSString * key in dict) {
        [whereArray addObject:[NSString stringWithFormat:@"%@ = ?", key]];
    }
    NSString * whereStr = [whereArray componentsJoinedByString:@" AND "];
    return whereStr;
}

删除记录

/**
 *  删除记录
 *
 *  @param tableName 表单名
 *  @param whereDict 字典,筛选的条件
 */
- (void)deleteRecordFromTable:(NSString *)tableName where:(NSDictionary *)whereDict
{
    [_lock lock];
    NSString * sql = nil;
    if (whereDict == nil) {
        sql = [NSString stringWithFormat:@"DELETE FROM %@", tableName];
        BOOL ret = [_database executeUpdate:sql];
        PERROR(ret, "delete whereDict");
        [_lock unlock];
        return;
    }
    
    //拼接筛选字符串
    NSString * whereStr = [self whereStringFromWhereDictionary:whereDict];
    
    //拼接SQL
    sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@", tableName, whereStr];
    BOOL ret = [_database executeUpdate:sql withArgumentsInArray:whereDict.allValues];
    PERROR(ret, "delete whereDict");
    [_lock unlock];
}
/**
 *  删除记录
 *
 *  @param tableName 表单名
 *  @param whereStr  用户自定议删除条件
 */
- (void)deleteRecordFromTable:(NSString *)tableName whereString:(NSString *)whereStr
{
    [_lock lock];
    NSString * sql = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@", tableName, whereStr];
    BOOL ret = [_database executeUpdate:sql];
    PERROR(ret, "delete whereStr");
    [_lock unlock];
}

 



查找数据

/**
 *  查看记录
 *
 *  @param columNames 数组
 *  @param tableName  表单名
 *  @param whereDict  字典
 *
 *  @return 查看结果
 */
- (FMResultSet *)select:(NSArray *)columNames fromTable:(NSString *)tableName where:(NSDictionary *)whereDict
{
    [_lock lock];
    //首先是列的字符串
    NSString * colStr = nil;
    if (columNames == nil) {
        colStr = @"*";
    } else {
        colStr = [columNames componentsJoinedByString:@","];
    }
    
    NSString * sql = nil;
    if (whereDict == nil) {
        sql = [NSString stringWithFormat:@"SELECT %@ FROM %@", colStr, tableName];
        FMResultSet * set = [_database executeQuery:sql];
        [_lock unlock];
        return set;
    }
    //拼接删选字符串
    NSString * whereStr = [self whereStringFromWhereDictionary:whereDict];
    //拼接SQL
    sql = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@", colStr, tableName, whereStr];
    
    FMResultSet * set = [_database executeQuery:sql withArgumentsInArray:whereDict.allValues];
    [_lock unlock];
    return set;
}

 

拼接更新字符串

//拼接更新的字符串
- (NSString *)updateStringFromUpdateDictionary:(NSDictionary *)dict
{
    //拼接删选的字符串
    NSMutableArray * whereArray = [NSMutableArray array];
    for (NSString * key in dict) {
        [whereArray addObject:[NSString stringWithFormat:@"%@ = ?", key]];
    }
    NSString * whereStr = [whereArray componentsJoinedByString:@","];
    return whereStr;
}

更新记录

/**
 *  更新记录
 *
 *  @param tableName  表单名
 *  @param updateDict 更新的记录
 *  @param whereDict  筛选条件
 */
- (void)updateTable:(NSString *)tableName records:(NSDictionary *)updateDict where:(NSDictionary *)whereDict
{
    [_lock lock];
    //拼接更新的字符串
    NSString * updateStr = [self updateStringFromUpdateDictionary:updateDict];
    
    //拼接筛选条件
    NSString * sql = nil;
    if (whereDict == nil) {
        sql = [NSString stringWithFormat:@"UPDATE %@ SET %@;", tableName, updateStr];
        BOOL ret = [_database executeUpdate:sql];
        PERROR(ret, "update");
        [_lock unlock];
        return;
    }
    
    //拼接whereStr
    NSString * whereStr = [self whereStringFromWhereDictionary:whereDict];
    sql = [NSString stringWithFormat:@"UPDATE %@ SET %@ WHERE %@;", tableName, updateStr, whereStr];
    //合体的数组
    NSArray * compArray = [updateDict.allValues arrayByAddingObjectsFromArray:whereDict.allValues];
    BOOL ret = [_database executeUpdate:sql withArgumentsInArray:compArray];
    PERROR(ret, "update");
    
    [_lock unlock];
}

 使用:

+ (void)test
{
    DataBaseManage * dbm = [[DataBaseManage alloc] initWithDataBasePath:@"/Users/wuhongxing/Desktop/GP03/day18/DataBase/XX.sqlite"];
    [dbm dropTable:@"男演员"];

    NSDictionary * colums = @{
                              @"姓名":@"varchar(128)",
                              @"国籍":@"varchar(128)"
                              };
    [dbm createTable:@"男演员" primaryKey:@"ID" primaryType:@"integer" otherColums:colums];
    
    [dbm insertRecordIntoTable:@"男演员" withColumsAndValues:@{@"姓名":@"刘德华", @"国籍":@"中国"}];
    [dbm insertRecordIntoTable:@"男演员" withColumsAndValues:@{@"姓名":@"郭富城", @"国籍":@"中国"}];
    [dbm insertRecordIntoTable:@"男演员" withColumsAndValues:@{@"姓名":@"威尔 史密斯", @"国籍":@"美国"}];
    
    [dbm deleteRecordFromTable:@"男演员" where:@{@"姓名":@"郭富城"}];
    
    [dbm updateTable:@"男演员" records:@{@"姓名":@"周杰伦", @"国籍":@"中国台湾", @"ID":@"2"} where:@{@"姓名":@"威尔 史密斯"}];
    
    FMResultSet * set = [dbm select:nil fromTable:@"男演员" where:nil];
    while ([set next]) {
        //依次循环一条记录
        //取出记录中的属性
        int ID = [set intForColumn:@"ID"];
        NSString * name = [set stringForColumn:@"姓名"];
        NSString * contry = [set stringForColumn:@"国籍"];
    }
    
}

 

iOS开发之数据持久化存储

标签:

原文地址:http://www.cnblogs.com/wuhongxing/p/4988854.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!