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<sqlite3.h>
  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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容

  • 前言 一、直接写入(writeToFile) 1.使用场景 生成plist文件,以字典的形式保存简单配置信息,如i...
    337b94dc718f阅读 815评论 0 0
  • 技术由来 数据持久化是iOS开发中必不可少的一项技能。因为开发中我们多会涉及到用户信息存储、文件存储、应用内容缓存...
    无神阅读 1,145评论 0 13
  • 在介绍存储方案之前有必要说下沙盒机制,详见:iOS中的沙盒目录 数据持久化,其实就是将数据写入到硬盘的方式,使得A...
    大米卡卡阅读 346评论 0 0
  • 种类: plist存储:使用XML键值对持久化,它适用于少量且数据基本不怎么改变的情况。 偏好存储:使用...
    恋空K阅读 371评论 0 2
  • 概论 所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据。在iOS开发中,...
    Leeson1989阅读 1,914评论 4 1