iOS数据持久化方案

1.iOS中数据存储方式

  • plist(NSArray/NSDictionary)
  • preference(NSUserDefaults)
  • NSCoding(NSKeyedArchiver/NSkeyedUnarchiver)
  • SQlite3
  • Core Data

优缺点分析

  • plist(属性列表)是一种XML格式的文件,如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用
    writeToFile:atomically:encoding:error:方法直接将对象写入属性列表文件中。但是对于自定义类无法使用,而且只能存储非常简单的数据。
  • preference(偏好设置)一般用来保存用户的账号、密码、字体大小等,也同样只能存储一些简单数据类型,无法存储自定义对象
  • 基于以上缺点,出现了NSCoding技术,NSCoding可以存储任何对象。只有遵守了NSCoding协议的对象,可以实现encodeWithCoder归档对象,initWithCoder恢复对象。
  • 以上三种存在致命缺陷,无法存储大量数据,也无法实现非常便捷的CRUD(增删改查)。每次操作都要从文件中读取数据到内存中,然后增删改查,再写入文件,以旧文件覆盖新文件。大量IO操作,非常耗费性能。
  • SQLite是纯C语言嵌入式关系型数据库,内存开销小、效率高,广泛使用于移动客户端。
  • Core Data基于SQList,是苹果推出的基于OC版本的数据库技术,比较庞大,比较重量级,包装了很多层,所以效率不及SQLite3。

2.SQLite基本操作

1.准备工作

背景:在storyboard上添加两个textField和label,用来输入商品数据的名称和价格,点击添加按钮后,将其插入数据库。

  1. 导入框架libsqlite3.0.tbd
  2. 包含主头文件#import
  3. 使用sqlite前先要打开数据库
    //创建数据库文件名shop.sqlite
NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:@"shop.sqlite"];
    //打开数据库
    int status = sqlite3_open(fileName.UTF8String, &_dataBase);
    if (status == SQLITE_OK) {//打开成功
        NSLog(@"打开数据库成功");
        //SQL创表语句,id字段:主键,name:名称,price:价格
        const char *sql = "CREATE TABLE IF NOT EXISTS t_shop (id integer PRIMARY KEY,name text NOT NULL,price real);";
        char *error = NULL;
        //执行sql语句
        sqlite3_exec(self.dataBase, sql, NULL, NULL, &error);
        if (error) {
            NSLog(@"创表失败:%s",error);
        }
    }else{
        NSLog(@"打开数据库失败");
    }

代码解析:sqlite3_open()将根据文件路径打开数据库,如果数据库文件不存在,系统会自动创建文件自动初始化数据库。如果返回值status等于常量SQLITE_OK,表示数据库打开成功。第二个参数_dataBase是该控制器sqlite3类型的属性,是一个打开的数据库实例。数据库文件的路径必须以C字符串(而非NSString)传入。一般服务器开发中打开数据库,都需要使用sqlite3_close(_dataBase)关闭数据库,但在移动开发中,可以不用。

2.插入数据

  //sql语句
NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_shop(name,price) VALUES('%@',%f);",self.nameField.text,self.priceField.text.doubleValue];
  //执行sql,nameField和priceField是两个textField输入控件
  sqlite3_exec(self.dataBase, sql.UTF8String, NULL, NULL, NULL);

代码分析:sqlite3_exec()可以执行任何sql语句,比如创表、更新、插入、删除操作等等。但一般不用它执行查询语句,因为它不会返回查询到的数据

3.查询数据

const char *sql = "SELECT name,price FROM t_shop";
//stmt指针是用来去除查询结果
sqlite3_stmt *stmt = NULL;
//准备
int status = sqlite3_prepare_v2(self.dataBase, sql, -1, &stmt, NULL);
if (status == SQLITE_OK) {//SQL语句正确,准备成功
      while (sqlite3_step(stmt)==SQLITE_ROW) {//成功取出一条数据
            const char *name = (const char *)sqlite3_column_text(stmt, 0);//取第一个字段
            const char *price = (const char *)sqlite3_column_text(stmt, 1);//q取第二个字段
            NSLog(@"%s,%s",name,price);
        }
    }
     sqlite3_finalize(stmt);//销毁sqlite3_stmt对象

代码解析:sqlite3_step()返回SQLITE_ROW代表遍历到一条新纪录,sqlite3_column_*()用于获取每个字段对应的值,第2个参数是字段的索引,从0开始。

4.模糊查找

    //searchText是需要查询的关键字
NSString *sql = [NSString stringWithFormat:@"SELECT name,price FROM t_shop WHERE name LIKE '%%%@%%' OR  price LIKE '%%%@%%' ;", searchText, searchText];
sqlite3_stmt *stmt = NULL;
    int status = sqlite3_prepare_v2(self.db, sql.UTF8String, -1, &stmt, NULL);
    if (status == SQLITE_OK) { 
        while (sqlite3_step(stmt) == SQLITE_ROW) { 
            const char *name = (const char *)sqlite3_column_text(stmt, 0);
            const char *price = (const char *)sqlite3_column_text(stmt, 1);
            NSLog(@"%s,%s",name,price);            
         }
    }
sqlite3_finalize(stmt);

代码分析:模糊查找与一般查找除了sql语句不同,其他都是一样的。唯一需要注意的是,在数据库中%表示任意东西,%S%表示字符S右边和左边可以是任何东西,在OC中%表示特殊意义,所以要写两个(%%)表示一个(%)。

5.sqlite函数总结

1.打开数据库
int sqlite3_open(
    const char *filename,   // 数据库的文件路径
    sqlite3 **ppDb          // 数据库实例
);

2.执行任何SQL语句
int sqlite3_exec(
    sqlite3 *,                                  // 一个打开的数据库实例
    const char *sql,                           // 需要执行的SQL语句
    int (*callback)(void*,int,char**,char**),  // SQL语句执行完毕后的回调
    void *,                                    // 回调函数的第1个参数
    char **errmsg                              // 错误信息
);

3.检查SQL语句的合法性(查询前的准备)
int sqlite3_prepare_v2(
    sqlite3 *db,            // 数据库实例
    const char *zSql,       // 需要检查的SQL语句
    int nByte,              // SQL语句的最大字节长度
    sqlite3_stmt **ppStmt,  // sqlite3_stmt实例,用来获得数据库数据
    const char **pzTail
);

4.查询一行数据
int sqlite3_step(sqlite3_stmt*); // 如果查询到一行数据,就会返回SQLITE_ROW

5.利用stmt获得某一字段的值(字段的下标从0开始)
double sqlite3_column_double(sqlite3_stmt*, int iCol);  // 浮点数据
int sqlite3_column_int(sqlite3_stmt*, int iCol); // 整型数据
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); // 长整型数据
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); // 二进制文本数据
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);  // 字符串数据

最后

第一篇博客,有很多问题,还没写全,如果想到了再做补充吧。使用这些sqlite原生的C语言API非常费力,以后有空介绍一下iOS中最常使用的数据库框架FMDB吧


That's All

你可能感兴趣的:(iOS数据持久化方案)