zoukankan      html  css  js  c++  java
  • iOS SQLite学习(上)

    前言:App的开发都七七八八了(当然还有大量的bug),基本功能是差不多都有了,有些地方可能比官方的还要好上一些(写了差不多3个月,比官方烂太多还真说不过去)。但是,作为移动应用,流畅和几乎无迟滞的体验会更受到用户欢迎。我的App问题就是,每一次都要向服务器请求json数据。虽然每次的数据量都不大,但等那么一两秒,长期下来,用户肯定会感到厌烦。而且,请求数据受到网络环境影响,等待的时间可能会更长,如果请求失败,估计摔手机的心都有了(我一般会直接删除应用)。同时,这么吃流量的怪兽,估计没多少个人会在非WiFi环境下使用,用户活跃数又随之减少了。以上就是我决心做缓存的原因。

     一、前期准备
    先添加开发包“libsqlite3.0.dylib”,然后在需要调用数据库的源文件加上“#import "/usr/include/sqlite3.h"”,最后一个就是起码对SQL语言有个大概的了解。我查阅了一下SQLite的一些资料,SQLite是针对嵌入设备设计的,属于轻量级的数据库,数据量不大的时候可以有相当不错的性能。对于iOS的设备而言,不可能进行大量的数据处理,毕竟CPU的性能就摆在那里。SQLite提供的是C语言的API,相信可以用于移植,同时生成的数据库也是兼容其他平台上的SQLite。不过,虽然使用C语言的API保证了效率和移植性,但是获取出来时的数据都是属于C的基本类型。对于使用Object-C的开发者来说,UI的各种控件几乎都需要用到Object-C的对象,那么就必须对这些数据做进一步的处理。还有,由于C语言的特性,所以写出来的代码也有一点臃肿(可能我的C还不够好)。此外,SQLite的数据库只有一个文件,管理起来不会很麻烦。SQLite操作的方法是,先建立一个与数据库文件链接的实例,然后再使用API来进行操作和获取返回数据。
    介绍一下,特有的类型吧:
     
    sqlite3     主要声明为指针,用于保存获取数库文件链接的实例,所有的操作都需要用到它,关闭数据库时会释放内存。
    sqlite3_stmt  主要声明为指针,可以理解为一条编译好的SQL语句,执行完成需要手动释放,否则会内存泄露。
     
    在暂时用到的就这两个类型,真的很简单。
     
    二、SQLite的API
    1.sqlite3_open()
    最开始用的肯定是这个方法了,作用是打开数据库的文件,通过改变第二个参数来获得操作数据库的实例,第一个参数则为数据库文件的位置(UTF8编码喔),成功就返回SQLITE_OK。
     
    2.sqlite3_prepare_v2()
    执行SQL语句需要用到的方法之一,也有sqlite3_prepare()旧版接口,不过不建议使用。推荐全部用新版接口,保留旧版只是为了以前版本的兼容性。这个方法的作用,就写好的SQL语句编译为sqlite3_stmt类型,为下面执行做准备(此时语句并未开始执行)。调用成功的话返回SQLITE_OK。
     
    3.sqlite3_step()
    调用这个方法才是真正地执行了SQL语句,如果非查询语句执行成功的话是会返回SQLITE_DONE。如果执行的是查询语句,返回SQLITE_DONE就意味着下面已经没有结果显示了。
     
    4.sqlite3_column_*()
    sqlite3_column类的一系列方法都是用来获取查询后的数据,但是前提是你必须要知道你将会获得的数据类型。因为方法必须和数据类型相匹配,否则你将无法获取正确的数据。此外,通过第二个参数来获取,同一行数据的不同列,0是最开始的列。如果有多行结果,就要通过不断执行sqlite3_step()来获取所有行的结果,直到sqlite3_step()的返回结果是SQLITE_DONE。
     
    5.sqlite3_finalize()
    释放sqlite3_stmt,如果使用完sqlite3_stmt不执行释放,就会造成内存泄露。不过,这里有一点值得注意,就是sqlite3_column_*()、sqlite3_finalize()和sqlite3_stmt这三者的关系。sqlite3_column_*()获取结果,本来是和sqlite3_finalize()没什么关系的,但事实并非如此。如果sqlite3_column_*()返回的是基本类型,那么何时调用sqlite3_finalize()都没有问题,但如果是字符串之类的,那就要注意了。SQLite使用的都是C级别的API,那么C没有真正的字符串类型的特性它也继承了。意味着在获取在获取字符串的时候,它为了内存不会被意外释放掉,那么它肯定是动态申请内存空间,然后把字符串放进去,最后才返回一个字符串的首地址。既然是动态申请空间,那么肯定要由自己来释放,那么释放的任务实际上就交给了sqlite3_finalize()。所以,如果要调用sqlite3_finalize(),必须保证自己的获取的字符串有拷贝(不是指针拷贝),或者确定不会再调用了,否则提前释放sqlite3_stmt会造成无法估计的错误。
     
    6.sqlite3_close()
    用来关闭已经打开了的数据库,也就是有释放内存的功能,最后不调用这个方法的话也是会内存泄露的。
     
    7.sqlite3_bind_*()
    用来绑定数据,避免重复使用sqlite3_prepare_v2(),可以提升效率。其中类似字符串的类型,sqlite3_bind_text()等方法会多一个参数,可以传SQLITE_STATIC或者SQLITE_TRANSIENT,前者代表传入的字符串为静态,不会被意外释放。后者则表示无法保证字符串是否被释放。
     
    8.sqlite3_exec()
    非查询语句也可以使用这个方法,不过需要在调用后free errmsg,否则也会造成内存泄露。
     

    三、SQLite的数据类型
    1.NULL
    就是表示空值。
    2.INTEGER
    表示无符号整数。
    3.REAL
    表示浮点数
    4.TEXT
    字符串类型,支持UTF8编码。
    5.BLOB
    二进制类型。
     
    此外SQLite没有专门的布尔类型和时间类型,布尔类型可以直接用整数类型代替,时间类型则可以用TEXT、REAL或者INTEGER。不过,在查询的时候,如果储存为时间,就可以使用更合适的时间比较,方便查询。其实时间类型我也暂时没有使用到,因为我的数据不需要直接使用SQL语句来比较时间,所以我只是直接储存为TEXT类型。
     
    四、使用例子
    打开数据库
    1 sqlite3 *dataBase = NULL;
    2 NSArray *documentsPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    3 NSString *databaseFilePath = [[documentsPaths objectAtIndex:0] stringByAppendingPathComponent:cache.sqlitedb];
    4     
    5 if (sqlite3_open([databaseFilePath UTF8String], &dataBase)==SQLITE_OK)
    6         NSLog(@"open sqlite db ok.");

    建立数据表

     1 const char *createCacheList = "CREATE TABLE IF NOT EXISTS "CACHELISTTABLE" (id TEXT PRIMARY KEY, cachedate TEXT)";
     2 sqlite3_stmt *createCacheListStmt = NULL;
     3 
     4 if (sqlite3_prepare_v2(dataBase, createCacheList, strlen(createCacheList), &createCacheListStmt, NULL) != SQLITE_OK) {
     5         
     6     if (createCacheListStmt)
     7         sqlite3_finalize(createCacheListStmt);
     8     return nil;
     9    
    10 }
    11 if (sqlite3_step(createCacheListStmt) != SQLITE_DONE) {
    12         
    13     sqlite3_finalize(createCacheListStmt);
    14     return nil;
    15         
    16 }
    17 sqlite3_finalize(createCacheListStmt);

    上面的例子都有做了异常处理,实际上,当你的数据来源是可预知,系统的文件系统是稳定可靠的话,可以省去上面的异常处理。省去异常处理的话,代码会更加简短、可读性更好,但是出现错误的时候更难找到出错的地方。

    暂时就先写这么多,还有进阶的内容下次继续写。

     
     
     
  • 相关阅读:
    POJ2352
    POJ 2524 并查集
    A POJ1611
    树状dp--B
    spring mvc实现文件上传与下载
    Joda-Time
    JAVA对象与JSON之间的转换
    jackson-databind注解
    JPA注解
    springMVC、spring、jpa、springData整合配置
  • 原文地址:https://www.cnblogs.com/ipinka/p/2735202.html
Copyright © 2011-2022 走看看