1.plist文件存储
每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问该沙盒
应用沙盒的文件系统目录,如下图所示(假设应用的名称叫Layer)
模拟器应用沙盒的根路径在: (apple是用户名, 6.0是模拟器版本)
/Users/apple/Library/Application Support/iPhone Simulator/6.0/Applications
Document :保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
temp :保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
Library/Caches :保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据
Library/Preference: 保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
示例代码:
缺点 : 只能存储含有 writeToFile:方法的对象,如NSDictionary,NSArray等 .
2.[b]NSUserDefaults( 偏好设置 ): [/b]
-- 存放目录 Library/Preference。
用来保存应用程序设置和属性、用户保存的数据,用户再次打开程序或开机后这些数据仍然存在。NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、 NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能,每个应用都有个NSUserDefaults实例,通过它来存取偏好设置
比如,保存用户名、字体大小、是否自动登录等。
示例代码:
注意 :UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入[defaults
synchornize];
缺点 : 本质还是plist文件存储,相对于plist文件存储来讲存储数据更快捷.
3.NSKeyedArchiver(NSCoding)
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复,不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
NSCoding协议有2个方法:
encodeWithCoder:每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量;
initWithCoder:每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量。
缺点 : 归档的形式来保存数据,只能一次性归档保存以及一次性解压。所以只能针对小量数据,而且对数据操作比较笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据 。
示例代码:
NSKeyedArchiver-归档对象的注意:
如果父类也遵守了NSCoding协议,请注意:
应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码, 也能被归档;
应该在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];确保继承的实例变量也能被解码,即也能被恢复;
但有时候可能想将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象,NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容。
示例代码:
1 Person.h里面
2
3 #import <Foundation/Foundation.h>
4
5 @interface Person : NSObject <NSCoding>
6
7 @property (nonatomic , copy) NSString *name;
8 @property (nonatomic , assign) int age;
9 @property (nonatomic , assign) double height;
10
11 @end
12
13 Person.m里面
14 #import "Person.h"
15
16 @implementation Person
17
18 //归档的时候调用
19 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/
20 - (void)encodeWithCoder:(NSCoder *)enCoder
21 {
22 NSLog(@"enCoder - %@",enCoder);
23 [enCoder encodeObject:self.name forKey:@"name"];
24 [enCoder encodeInt:self.age forKey:@"age"];
25 [enCoder encodeDouble:self.height forKey:@"height"];
26
27 }
28
29 /** 解档时候调用,在这个方法中说清楚哪些属性要解档*/
30 - (id)initWithCoder:(NSCoder *)decoder
31 {
32 if (self = [super init])
33 {
34 //读取文件内容
35
self.name= [decoder decodeObjectForKey:@"name"];
36 self.age = [decoder decodeIntForKey:@"age"];
37 self.height = [decoder decodeDoubleForKey:@"height"];
38
39 }
40
41 return self;
42 }
43
44
45 @end
46
47 SDViewController.m里面
48
49 #import "SDViewController.h"
50 #import "Person.h"
51
52 @interface SDViewController ()
53
54 @end
55
56 @implementation SDViewController
57
58 - (void)viewDidLoad
59 {
60 [super viewDidLoad];
61 // Do any additional setup after loading the view, typically from a nib.
62
63 }
64
65 - (void)didReceiveMemoryWarning
66 {
67 [super didReceiveMemoryWarning];
68 // Dispose of any resources that can be recreated.
69 }
70
71
72 - (IBAction)save
73 {
74 //1.数据对象
75 Person *p1 = [[Person alloc] init];
76 p1.name = @"王麻子";
77 p1.age = 20;
78 p1.height = 1.98;
79 Person *p2 = [[Person alloc] init];
80 p2.name = @"李四";
81 p2.age = 56;
82 p2.height = 1.68;
83 //2.归档数据对象
84 //2.1获得文件的Documents全路径
85 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
86 //2.2获得文件的全路径
87 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
88 //
//2.3将对象归档
89 // [NSKeyedArchiver archiveRootObject:p1 toFile:path];
90 //
91 // 新建一块可变数据区
92 NSMutableData *data = [NSMutableData data];
93 // 将数据区连接到一个NSKeyedArchiver对象
94 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
95 [archiver encodeObject:p1 forKey:@"person1"];
96 [archiver encodeObject:p2 forKey:@"person2"];
97 // 存档完毕(一定要调用这个方法)
98 [archiver finishEncoding];
99 //将存档的数据写入文件
100 [data writeToFile:path atomically:YES];
101
102 }
103 - (IBAction)read
104 {
105 // 1.获得Documents的全路径
106 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
107 // 2.获得文件的全路径
108 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
109 // 3.从文件中读取Student对象
110 // Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
111 NSData *data = [NSData dataWithContentsOfFile:path];
112
113 // 根据数据,解析成一个NSKeyedUnarchiver对象
114 NSKeyedUnarchiver *unchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
115 Person *p1 = [unchiver decodeObjectForKey:@"person1"];
116 Person *p2 = [unchiver decodeObjectForKey:@"person2"];
117 [unchiver finishDecoding];
118 NSLog(@"%@ %d %f", p1.name, p1.age, p1.height);
119 NSLog(@"%@ %d %f", p2.name, p2.age, p2.height);
120
121 }
122
123
124
125 @end
附:
NSCoder.h
- (void)encodeValueOfObjCType:(const char *)type at:(const void *)addr; //解档C类型数据,addr传入地址
- (void)encodeDataObject:(NSData *)data; //归档一个NSData型对象
- (void)decodeValueOfObjCType:(const char *)type at:(void *)data; 解档C类型数据
- (NSData *)decodeDataObject;//解档一个NSData型对象
@end
@interface NSCoder (NSExtendedCoder)
/** 归档相关函数*/
- (void)encodeObject:(id)object;
- (void)encodeRootObject:(id)rootObject;
- (void)encodeBycopyObject:(id)anObject;
- (void)encodeByrefObject:(id)anObject;
- (void)encodeConditionalObject:(id)object;
- (void)encodeValuesOfObjCTypes:(const char *)types, ...;
- (void)encodeArrayOfObjCType:(const char *)type count:(NSUInteger)count at:(const void *)array;
- (void)encodeBytes:(const void *)byteaddr length:(NSUInteger)length;
/** 解档相关函数*/
- (id)decodeObject;
- (void)decodeValuesOfObjCTypes:(const char *)types, ...;
- (void)decodeArrayOfObjCType:(const char *)itemType count:(NSUInteger)count at:(void *)array;
- (void *)decodeBytesWithReturnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER;
- (unsigned)systemVersion;
//是否遵循KeyedCoding
- (BOOL)allowsKeyedCoding;
/** 归档相关函数*/
- (void)encodeObject:(id)objv forKey:(NSString *)key;
- (void)encodeConditionalObject:(id)objv forKey:(NSString *)key;
- (void)encodeBool:(BOOL)boolv forKey:(NSString *)key;
- (void)encodeInt:(int)intv forKey:(NSString *)key;
- (void)encodeInt32:(int32_t)intv forKey:(NSString *)key;
- (void)encodeInt64:(int64_t)intv forKey:(NSString *)key;
- (void)encodeFloat:(float)realv forKey:(NSString *)key;
- (void)encodeDouble:(double)realv forKey:(NSString *)key;
- (void)encodeBytes:(const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(NSString *)key;
/** 解档相关函数*/
- (BOOL)containsValueForKey:(NSString *)key;
- (id)decodeObjectForKey:(NSString *)key;
- (BOOL)decodeBoolForKey:(NSString *)key;
- (int)decodeIntForKey:(NSString *)key;
- (int32_t)decodeInt32ForKey:(NSString *)key;
- (int64_t)decodeInt64ForKey:(NSString *)key;
- (float)decodeFloatForKey:(NSString *)key;
- (double)decodeDoubleForKey:(NSString *)key;
- (const uint8_t *)decodeBytesForKey:(NSString *)key returnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER; // returned bytes immutable!
- (void)encodeInteger:(NSInteger)intv forKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);
- (NSInteger)decodeIntegerForKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);
// Returns YES if this coder requires secure coding. Secure coders check a list of allowed classes before decoding objects, and all objects must implement NSSecureCoding.
//是否安全解档
- (BOOL)requiresSecureCoding NS_AVAILABLE(10_8, 6_0);
4. Write写入方式 :永久保存在磁盘中。
具体方法为:
[b]第一步:获得文件即将保存的路径: [/b]
方法1:
NSArray*documentPaths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
//使用C函数NSSearchPathForDirectoriesInDomains来获得沙盒中目录的全路径。该函数有三个参数,目录类型、he domain mask、布尔值。其中布尔值表示是否需要通过“~”扩展路径。而且第一个参数是不变的,即为NSSearchPathDirectory。在IOS中后两个参数也是不变的,即为:NSUserDomainMask和YES。
NSString *ourDocumentPath =[documentPaths objectAtIndex:0];
方法2:
使用NSHomeDirectory函数获得sandbox的路径。
具体的用法为:
NSString *sandboxPath = NSHomeDirectory();// Once you have the fullsandbox path, you can create a path from it,但是不能在sandbox的本文件层上写文件也不能创建目录,而应该是此基础上创建一个新的可写的目录,例如Documents,Library或者temp。
NSString *documentPath = [sandboxPath stringByAppendingPathComponent:@"Documents"];//将Documents添加到sandbox路径上,具体原因前面分析了!
区别: 使用NSSearchPathForDirectoriesInDomains比在NSHomeDirectory后面添加Document更加安全。因为该文件目录可能在未来发送的系统上发生改变。
第二步:生成在该路径下的文件:
NSString *FileName=[documentDirectory stringByAppendingPathComponent:fileName];//fileName就是保存文件的文件名
第三步:往文件中写入数据:
[datawriteToFile:FileName atomically:YES];//将NSData类型对象data写入文件,文件名为FileName
最后:从文件中读出数据:
NSDatadata=[NSDatadataWithContentsOfFile:FileName options:0 error:NULL];//从FileName中读取出数据
5.SQLite3
SQLite3是一款开源的嵌入式关系型数据库,可移植性好、易使用、内存开销小.SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中。
数据库语句
/*简单约束*/
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER);
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型不能为空,age integer类型不能为空);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER NOT NULL);
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,并且每一个是唯一的,age integer类型不能为空);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER);
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型默认为1);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER DEFAULT 1);
/*分页*/
//先将表按照升序排,跳过最前面30条语句,然后取10条记录
SELECT * FROM t_student ORDER BY id ASC LIMIT 30, 10;
/*排序*/
//取出表中score > 50的数据并按照降序排列
SELECT * FROM t_student WHERE score > 50 ORDER BY age DESC;
//取出表中score<50的数据并按照升序排列,score>50的数据按照降序排列
SELECT * FROM t_student WHERE score < 50 ORDER BY age ASC , score DESC;
/*计量*/
//统计表中age > 50的个数
SELECT COUNT(*) FROM t_student WHERE age > 50;
/*别名*/
//将name 命名为 myName, age 命名为 myAge, score 命名为myScore
SELECT name as myName, age as myAge, score as myScore FROM t_student;
//将name 命名为 myName, age 命名为 myAge, score 命名为myScore
SELECT name myName, age myAge, score myScore FROM t_student;
//给t_student表起个别名叫做s,利用s来引用表中的字段,取出age > 50 的数据,将name 命名为 myName, age 命名为 myAge, score 命名为myScore
SELECT s.name myName, s.age myAge, s.score myScore FROM t_student s WHERE s.age > 50;
/*查询*/
//从表中查询name,age,score
SELECT name, age, score FROM t_student;
//查询整张表
SELECT * FROM t_student;
/*修改指定数据*/
//从表中取出age = 10 的那条数据,将name 字段值设为MM
UPDATE t_student SET name = 'MM' WHERE age = 10;
/从表中取出age = 7 的那条数据,将name 字段值设为WW
UPDATE t_student SET name = 'WW' WHERE age is 7;
//取出表中age < 20 的数据,并将name 全部设置为XXOO
UPDATE t_student SET name = 'XXOO' WHERE age < 20;
//取出表中age < 50 并且 score > 10的数据,将满足条件的每一条数据中的name字段设置为NNMM
UPDATE t_student SET name = 'NNMM' WHERE age < 50 and score > 10;
/*删除数据*/
//删除表中的数据
DELETE FROM t_student;
/*更新数据*/
//将表中的name字段全部设置为MM
UPDATE t_student SET name = 'MM';
/*插入数据*/
//往表中插入一条数据(name = jonathan , age = 28, score = 100)
INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'jonathan');
//往表中插入一条数据(name = lee , age = 28)
INSERT INTO t_student(name, age) VALUES ('lee', '28');
//往表中插入一条数据(score = 100)
INSERT INTO t_student(score) VALUES (100);
/*添加主键*/
//如果表不存在就创建一张表,id为主键自动增长,integer类型,name 为text类型,age 为integer类型,score为浮点类型
CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, score REAL);
/*删除表*/
//销毁t_student表
DROP TABLE t_student;
//如果表存在就销毁这张表
DROP TABLE IF EXISTS t_student;
/****************************************************** 应 用 *****************************************************************/
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.打开创建一个数据库
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"];
int result = sqlite3_open(fileName.UTF8String, &_db);
if (result == SQLITE_OK) {
// 创建表
const char *sql = "CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , name TEXT NOT NULL, age INTERGER NOT NULL);";
char *error = nil;
sqlite3_exec(self.db, sql, NULL, NULL, &error);
if (error) {
NSLog(@"创建失败");
}else{
NSLog(@"创建成功");
}
}else{
NSLog(@"失败");
}
}
/**
* 增加
*/
- (IBAction)insertBtnClick:(id)sender {
for (int i = 0; i < 100; i++) {
NSString *name = [NSString stringWithFormat:@"lee-%d", i];
int age = arc4random_uniform(50) + 50;
NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_student(name, age) VALUES ('%@', %d);", name, age];
char *error = nil;
sqlite3_exec(self.db, sql.UTF8String, NULL, NULL, &error);
if (error) {
NSLog(@"创建失败");
}else{
NSLog(@"创建成功");
}
}
}
/**
* 更新
*/
- (IBAction)updateBtnClick:(id)sender {
const char *sql = "UPDATE t_student SET name = 'DG';";
char *error = nil;
sqlite3_exec(self.db, sql, NULL, NULL, &error);
if (error) {
NSLog(@"更新失败");
}else{
NSLog(@"更新成功");
}
}
/**
* 删除
*/
- (IBAction)deleteBtnClick:(id)sender {
const char *sql = "DELETE FROM t_student;";
char *error = nil;
sqlite3_exec(self.db, sql, NULL, NULL, &error);
if (error) {
NSLog(@"删除失败");
}else{
NSLog(@"删除成功");
}
}
/**
* 查询
*/
- (IBAction)selectBtnClick:(id)sender {
const char *zSql = "SELECT * FROM t_student";
sqlite3_stmt *stmt;
// 查询前的准备, 检查sql语句是否正确
int result = sqlite3_prepare_v2(self.db, zSql, -1, &stmt, NULL);
if(result == SQLITE_OK) { // 准备完成,没有错误
// 提取查询到得数据到stmt, 一次提取一条
while(sqlite3_step(stmt) == SQLITE_ROW){
// 取出提取到得记录(数据)中的第0列数据和第一列数据
const unsigned char *name = sqlite3_column_text(stmt, 0);
int age = sqlite3_column_int(stmt, 1);
NSLog(@"%s, %d", name, age);
}
}
}
SqLite3小结
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); // 字符串数据
6.SqLite3第三方框架FMDB使用小结
FMDB是iOS平台的SQLite数据库框架,FMDB以OC的方式封装了SQLite的C语言API.
FMDB的优点
@1使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
@2对比苹果自带的Core Data框架,更加轻量级和灵活
@3提供了多线程安全的数据库操作方法,有效地防止数据混乱
每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问该沙盒
应用沙盒的文件系统目录,如下图所示(假设应用的名称叫Layer)
模拟器应用沙盒的根路径在: (apple是用户名, 6.0是模拟器版本)
/Users/apple/Library/Application Support/iPhone Simulator/6.0/Applications
Document :保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
temp :保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
Library/Caches :保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据
Library/Preference: 保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
示例代码:
1 /** 保存数据*/ 2 - (IBAction)saveBtn 3 { 4 NSLog(@"保存"); 5 //1.获取沙盒根路径 6 NSString *homePath = NSHomeDirectory(); 7 //2.document路径 8 NSString *path = [homePath stringByAppendingPathComponent:@"Documents"]; 9 //3.新建数据10 NSArray *array = [NSArray arrayWithObjects:@"nan",@(22), nil];11 NSDictionary *dict = @{@"sss":@"sddd",@"ssssaw":@(1222)};12 13 14 //4.存储数据15 NSString *fullPath1 = [path stringByAppendingPathComponent:@"data1.plist"];16 NSString *fullPath2 = [path stringByAppendingPathComponent:@"data2.plist"];17 18 [array writeToFile:fullPath1 atomically:YES]; //数组写入plist19 [dict writeToFile:fullPath2 atomically:YES];20 21 NSLog(@"dict - %@",dict);22 }23 24 /** 读取数据*/25 - (IBAction)readBtn26 {27 //1.获取home目录28 NSString *home = NSHomeDirectory();29 //2.拼接Document目录30 NSString *path = [home stringByAppendingPathComponent:@"Documents"];31 //3.文件路径32 NSString *filePath1 = [path stringByAppendingPathComponent:@"data1.plist"];33 NSString *filePath2 = [path stringByAppendingPathComponent:@"data2.plist"];34 //读取文件35 NSArray *array = [NSArray arrayWithContentsOfFile:filePath1];36 NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath2];37 NSLog(@"array - %@, dict - %@",array , dict);38 }
缺点 : 只能存储含有 writeToFile:方法的对象,如NSDictionary,NSArray等 .
2.[b]NSUserDefaults( 偏好设置 ): [/b]
-- 存放目录 Library/Preference。
用来保存应用程序设置和属性、用户保存的数据,用户再次打开程序或开机后这些数据仍然存在。NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、 NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能,每个应用都有个NSUserDefaults实例,通过它来存取偏好设置
比如,保存用户名、字体大小、是否自动登录等。
示例代码:
/** 保存数据*/- (IBAction)save{ // 1.利用NSUserDefaults,就能直接访问软件的偏好设置(Library/Preferences)是个单例对象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; //2.存储数据 [defaults setObject:@"sd" forKey:@"user"]; [defaults setObject:@"123w" forKey:@"test"]; [defaults setInteger:20 forKey:@"age"]; [defaults setBool:YES forKey:@"auto_login"]; //3.立刻同步(相当于更新数据) [defaults synchronize]; }/** 读取数据*/- (IBAction)read{ //1.建立NSUserDefaults对象 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; //2.读取数据 NSString *user = [defaults objectForKey:@"user"]; NSString *test = [defaults objectForKey:@"test"]; NSInteger age = [defaults integerForKey:@"age"]; BOOL autoLogin = [defaults boolForKey:@"auto_login"];NSLog(@"user - %@/n test - %@/n age - %d/n autoLogin - %d/n,",user,test,age,autoLogin);}
注意 :UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入[defaults
synchornize];
缺点 : 本质还是plist文件存储,相对于plist文件存储来讲存储数据更快捷.
3.NSKeyedArchiver(NSCoding)
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复,不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
NSCoding协议有2个方法:
encodeWithCoder:每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量;
initWithCoder:每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量。
缺点 : 归档的形式来保存数据,只能一次性归档保存以及一次性解压。所以只能针对小量数据,而且对数据操作比较笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据 。
示例代码:
1 #import <Foundation/Foundation.h> 2 3 @interface Person : NSObject <NSCoding> 4 5 @property (nonatomic , copy) NSString *name; 6 @property (nonatomic , assign) int age; 7 @property (nonatomic , assign) double height; 8 9 @end10 11 12 #import "Person.h"13 14 @implementation Person15 16 //归档的时候调用17 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/18 - (void)encodeWithCoder:(NSCoder *)enCoder19 {20 NSLog(@"enCoder - %@",enCoder);21 [enCoder encodeObject:self.name forKey:@"name"];22 [enCoder encodeInt:self.age forKey:@"age"];23 [enCoder encodeDouble:self.height forKey:@"height"];24 25 }26 27 /** 解档时候调用,在这个方法中说清楚哪些属性要解档*/28 - (id)initWithCoder:(NSCoder *)decoder29 {30 if (self = [super init])31 {32 //读取文件内容33 self.name = [decoder decodeObjectForKey:@"name"];34 self.age = [decoder decodeIntForKey:@"age"];35 self.height = [decoder decodeDoubleForKey:@"height"];36 37 }38 39 return self;40 }41 42 43 @end44 45 46 #import "SDViewController.h"47 #import "Person.h"48 49 @interface SDViewController ()50 51 @end52 53 @implementation SDViewController54 55 - (void)viewDidLoad56 {57 [super viewDidLoad];58 59 60 }61 62 - (IBAction)save63 {64 //1.数据对象65 Person *p1 = [[Person alloc] init];66 p1.name = @"王麻子";67 p1.age = 20;68 p1.height = 1.98;69 Person *p2 = [[Person alloc] init];70 p2.name = @"李四";71 p2.age = 56;72 p2.height = 1.68;73 //2.归档数据对象74 //2.1获得文件的Documents全路径75 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];76 //2.2获得文件的全路径77 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];78 //2.3将对象归档79 [NSKeyedArchiver archiveRootObject:p1 toFile:path];80 81 }82 - (IBAction)read83 {84 // 1.获得Documents的全路径85 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];86 // 2.获得文件的全路径87 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];88 // 3.从文件中读取Person对象89 Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];90 91 NSLog(@"%@ %d %f", p3.name, p3.age, p3.height);92 93 }94 95 96 @end
NSKeyedArchiver-归档对象的注意:
如果父类也遵守了NSCoding协议,请注意:
应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码, 也能被归档;
应该在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];确保继承的实例变量也能被解码,即也能被恢复;
但有时候可能想将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象,NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容。
示例代码:
1 Person.h里面
2
3 #import <Foundation/Foundation.h>
4
5 @interface Person : NSObject <NSCoding>
6
7 @property (nonatomic , copy) NSString *name;
8 @property (nonatomic , assign) int age;
9 @property (nonatomic , assign) double height;
10
11 @end
12
13 Person.m里面
14 #import "Person.h"
15
16 @implementation Person
17
18 //归档的时候调用
19 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/
20 - (void)encodeWithCoder:(NSCoder *)enCoder
21 {
22 NSLog(@"enCoder - %@",enCoder);
23 [enCoder encodeObject:self.name forKey:@"name"];
24 [enCoder encodeInt:self.age forKey:@"age"];
25 [enCoder encodeDouble:self.height forKey:@"height"];
26
27 }
28
29 /** 解档时候调用,在这个方法中说清楚哪些属性要解档*/
30 - (id)initWithCoder:(NSCoder *)decoder
31 {
32 if (self = [super init])
33 {
34 //读取文件内容
35
self.name= [decoder decodeObjectForKey:@"name"];
36 self.age = [decoder decodeIntForKey:@"age"];
37 self.height = [decoder decodeDoubleForKey:@"height"];
38
39 }
40
41 return self;
42 }
43
44
45 @end
46
47 SDViewController.m里面
48
49 #import "SDViewController.h"
50 #import "Person.h"
51
52 @interface SDViewController ()
53
54 @end
55
56 @implementation SDViewController
57
58 - (void)viewDidLoad
59 {
60 [super viewDidLoad];
61 // Do any additional setup after loading the view, typically from a nib.
62
63 }
64
65 - (void)didReceiveMemoryWarning
66 {
67 [super didReceiveMemoryWarning];
68 // Dispose of any resources that can be recreated.
69 }
70
71
72 - (IBAction)save
73 {
74 //1.数据对象
75 Person *p1 = [[Person alloc] init];
76 p1.name = @"王麻子";
77 p1.age = 20;
78 p1.height = 1.98;
79 Person *p2 = [[Person alloc] init];
80 p2.name = @"李四";
81 p2.age = 56;
82 p2.height = 1.68;
83 //2.归档数据对象
84 //2.1获得文件的Documents全路径
85 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
86 //2.2获得文件的全路径
87 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
88 //
//2.3将对象归档
89 // [NSKeyedArchiver archiveRootObject:p1 toFile:path];
90 //
91 // 新建一块可变数据区
92 NSMutableData *data = [NSMutableData data];
93 // 将数据区连接到一个NSKeyedArchiver对象
94 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
95 [archiver encodeObject:p1 forKey:@"person1"];
96 [archiver encodeObject:p2 forKey:@"person2"];
97 // 存档完毕(一定要调用这个方法)
98 [archiver finishEncoding];
99 //将存档的数据写入文件
100 [data writeToFile:path atomically:YES];
101
102 }
103 - (IBAction)read
104 {
105 // 1.获得Documents的全路径
106 NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
107 // 2.获得文件的全路径
108 NSString *path = [doc stringByAppendingPathComponent:@"person.txt"];
109 // 3.从文件中读取Student对象
110 // Person *p3 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
111 NSData *data = [NSData dataWithContentsOfFile:path];
112
113 // 根据数据,解析成一个NSKeyedUnarchiver对象
114 NSKeyedUnarchiver *unchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
115 Person *p1 = [unchiver decodeObjectForKey:@"person1"];
116 Person *p2 = [unchiver decodeObjectForKey:@"person2"];
117 [unchiver finishDecoding];
118 NSLog(@"%@ %d %f", p1.name, p1.age, p1.height);
119 NSLog(@"%@ %d %f", p2.name, p2.age, p2.height);
120
121 }
122
123
124
125 @end
附:
NSCoder.h
- (void)encodeValueOfObjCType:(const char *)type at:(const void *)addr; //解档C类型数据,addr传入地址
- (void)encodeDataObject:(NSData *)data; //归档一个NSData型对象
- (void)decodeValueOfObjCType:(const char *)type at:(void *)data; 解档C类型数据
- (NSData *)decodeDataObject;//解档一个NSData型对象
@end
@interface NSCoder (NSExtendedCoder)
/** 归档相关函数*/
- (void)encodeObject:(id)object;
- (void)encodeRootObject:(id)rootObject;
- (void)encodeBycopyObject:(id)anObject;
- (void)encodeByrefObject:(id)anObject;
- (void)encodeConditionalObject:(id)object;
- (void)encodeValuesOfObjCTypes:(const char *)types, ...;
- (void)encodeArrayOfObjCType:(const char *)type count:(NSUInteger)count at:(const void *)array;
- (void)encodeBytes:(const void *)byteaddr length:(NSUInteger)length;
/** 解档相关函数*/
- (id)decodeObject;
- (void)decodeValuesOfObjCTypes:(const char *)types, ...;
- (void)decodeArrayOfObjCType:(const char *)itemType count:(NSUInteger)count at:(void *)array;
- (void *)decodeBytesWithReturnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER;
- (unsigned)systemVersion;
//是否遵循KeyedCoding
- (BOOL)allowsKeyedCoding;
/** 归档相关函数*/
- (void)encodeObject:(id)objv forKey:(NSString *)key;
- (void)encodeConditionalObject:(id)objv forKey:(NSString *)key;
- (void)encodeBool:(BOOL)boolv forKey:(NSString *)key;
- (void)encodeInt:(int)intv forKey:(NSString *)key;
- (void)encodeInt32:(int32_t)intv forKey:(NSString *)key;
- (void)encodeInt64:(int64_t)intv forKey:(NSString *)key;
- (void)encodeFloat:(float)realv forKey:(NSString *)key;
- (void)encodeDouble:(double)realv forKey:(NSString *)key;
- (void)encodeBytes:(const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(NSString *)key;
/** 解档相关函数*/
- (BOOL)containsValueForKey:(NSString *)key;
- (id)decodeObjectForKey:(NSString *)key;
- (BOOL)decodeBoolForKey:(NSString *)key;
- (int)decodeIntForKey:(NSString *)key;
- (int32_t)decodeInt32ForKey:(NSString *)key;
- (int64_t)decodeInt64ForKey:(NSString *)key;
- (float)decodeFloatForKey:(NSString *)key;
- (double)decodeDoubleForKey:(NSString *)key;
- (const uint8_t *)decodeBytesForKey:(NSString *)key returnedLength:(NSUInteger *)lengthp NS_RETURNS_INNER_POINTER; // returned bytes immutable!
- (void)encodeInteger:(NSInteger)intv forKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);
- (NSInteger)decodeIntegerForKey:(NSString *)key NS_AVAILABLE(10_5, 2_0);
// Returns YES if this coder requires secure coding. Secure coders check a list of allowed classes before decoding objects, and all objects must implement NSSecureCoding.
//是否安全解档
- (BOOL)requiresSecureCoding NS_AVAILABLE(10_8, 6_0);
4. Write写入方式 :永久保存在磁盘中。
具体方法为:
[b]第一步:获得文件即将保存的路径: [/b]
方法1:
NSArray*documentPaths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
//使用C函数NSSearchPathForDirectoriesInDomains来获得沙盒中目录的全路径。该函数有三个参数,目录类型、he domain mask、布尔值。其中布尔值表示是否需要通过“~”扩展路径。而且第一个参数是不变的,即为NSSearchPathDirectory。在IOS中后两个参数也是不变的,即为:NSUserDomainMask和YES。
NSString *ourDocumentPath =[documentPaths objectAtIndex:0];
方法2:
使用NSHomeDirectory函数获得sandbox的路径。
具体的用法为:
NSString *sandboxPath = NSHomeDirectory();// Once you have the fullsandbox path, you can create a path from it,但是不能在sandbox的本文件层上写文件也不能创建目录,而应该是此基础上创建一个新的可写的目录,例如Documents,Library或者temp。
NSString *documentPath = [sandboxPath stringByAppendingPathComponent:@"Documents"];//将Documents添加到sandbox路径上,具体原因前面分析了!
区别: 使用NSSearchPathForDirectoriesInDomains比在NSHomeDirectory后面添加Document更加安全。因为该文件目录可能在未来发送的系统上发生改变。
第二步:生成在该路径下的文件:
NSString *FileName=[documentDirectory stringByAppendingPathComponent:fileName];//fileName就是保存文件的文件名
第三步:往文件中写入数据:
[datawriteToFile:FileName atomically:YES];//将NSData类型对象data写入文件,文件名为FileName
最后:从文件中读出数据:
NSDatadata=[NSDatadataWithContentsOfFile:FileName options:0 error:NULL];//从FileName中读取出数据
5.SQLite3
SQLite3是一款开源的嵌入式关系型数据库,可移植性好、易使用、内存开销小.SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中。
数据库语句
/*简单约束*/
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER);
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型不能为空,age integer类型不能为空);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, age INTEGER NOT NULL);
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,并且每一个是唯一的,age integer类型不能为空);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, age INTEGER);
//如果表不存在就创建一张t_student的表(id为主键,自动增长,name text类型,age integer类型默认为1);
CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER DEFAULT 1);
/*分页*/
//先将表按照升序排,跳过最前面30条语句,然后取10条记录
SELECT * FROM t_student ORDER BY id ASC LIMIT 30, 10;
/*排序*/
//取出表中score > 50的数据并按照降序排列
SELECT * FROM t_student WHERE score > 50 ORDER BY age DESC;
//取出表中score<50的数据并按照升序排列,score>50的数据按照降序排列
SELECT * FROM t_student WHERE score < 50 ORDER BY age ASC , score DESC;
/*计量*/
//统计表中age > 50的个数
SELECT COUNT(*) FROM t_student WHERE age > 50;
/*别名*/
//将name 命名为 myName, age 命名为 myAge, score 命名为myScore
SELECT name as myName, age as myAge, score as myScore FROM t_student;
//将name 命名为 myName, age 命名为 myAge, score 命名为myScore
SELECT name myName, age myAge, score myScore FROM t_student;
//给t_student表起个别名叫做s,利用s来引用表中的字段,取出age > 50 的数据,将name 命名为 myName, age 命名为 myAge, score 命名为myScore
SELECT s.name myName, s.age myAge, s.score myScore FROM t_student s WHERE s.age > 50;
/*查询*/
//从表中查询name,age,score
SELECT name, age, score FROM t_student;
//查询整张表
SELECT * FROM t_student;
/*修改指定数据*/
//从表中取出age = 10 的那条数据,将name 字段值设为MM
UPDATE t_student SET name = 'MM' WHERE age = 10;
/从表中取出age = 7 的那条数据,将name 字段值设为WW
UPDATE t_student SET name = 'WW' WHERE age is 7;
//取出表中age < 20 的数据,并将name 全部设置为XXOO
UPDATE t_student SET name = 'XXOO' WHERE age < 20;
//取出表中age < 50 并且 score > 10的数据,将满足条件的每一条数据中的name字段设置为NNMM
UPDATE t_student SET name = 'NNMM' WHERE age < 50 and score > 10;
/*删除数据*/
//删除表中的数据
DELETE FROM t_student;
/*更新数据*/
//将表中的name字段全部设置为MM
UPDATE t_student SET name = 'MM';
/*插入数据*/
//往表中插入一条数据(name = jonathan , age = 28, score = 100)
INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'jonathan');
//往表中插入一条数据(name = lee , age = 28)
INSERT INTO t_student(name, age) VALUES ('lee', '28');
//往表中插入一条数据(score = 100)
INSERT INTO t_student(score) VALUES (100);
/*添加主键*/
//如果表不存在就创建一张表,id为主键自动增长,integer类型,name 为text类型,age 为integer类型,score为浮点类型
CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, score REAL);
/*删除表*/
//销毁t_student表
DROP TABLE t_student;
//如果表存在就销毁这张表
DROP TABLE IF EXISTS t_student;
/****************************************************** 应 用 *****************************************************************/
- (void)viewDidLoad
{
[super viewDidLoad];
// 1.打开创建一个数据库
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"];
int result = sqlite3_open(fileName.UTF8String, &_db);
if (result == SQLITE_OK) {
// 创建表
const char *sql = "CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , name TEXT NOT NULL, age INTERGER NOT NULL);";
char *error = nil;
sqlite3_exec(self.db, sql, NULL, NULL, &error);
if (error) {
NSLog(@"创建失败");
}else{
NSLog(@"创建成功");
}
}else{
NSLog(@"失败");
}
}
/**
* 增加
*/
- (IBAction)insertBtnClick:(id)sender {
for (int i = 0; i < 100; i++) {
NSString *name = [NSString stringWithFormat:@"lee-%d", i];
int age = arc4random_uniform(50) + 50;
NSString *sql = [NSString stringWithFormat:@"INSERT INTO t_student(name, age) VALUES ('%@', %d);", name, age];
char *error = nil;
sqlite3_exec(self.db, sql.UTF8String, NULL, NULL, &error);
if (error) {
NSLog(@"创建失败");
}else{
NSLog(@"创建成功");
}
}
}
/**
* 更新
*/
- (IBAction)updateBtnClick:(id)sender {
const char *sql = "UPDATE t_student SET name = 'DG';";
char *error = nil;
sqlite3_exec(self.db, sql, NULL, NULL, &error);
if (error) {
NSLog(@"更新失败");
}else{
NSLog(@"更新成功");
}
}
/**
* 删除
*/
- (IBAction)deleteBtnClick:(id)sender {
const char *sql = "DELETE FROM t_student;";
char *error = nil;
sqlite3_exec(self.db, sql, NULL, NULL, &error);
if (error) {
NSLog(@"删除失败");
}else{
NSLog(@"删除成功");
}
}
/**
* 查询
*/
- (IBAction)selectBtnClick:(id)sender {
const char *zSql = "SELECT * FROM t_student";
sqlite3_stmt *stmt;
// 查询前的准备, 检查sql语句是否正确
int result = sqlite3_prepare_v2(self.db, zSql, -1, &stmt, NULL);
if(result == SQLITE_OK) { // 准备完成,没有错误
// 提取查询到得数据到stmt, 一次提取一条
while(sqlite3_step(stmt) == SQLITE_ROW){
// 取出提取到得记录(数据)中的第0列数据和第一列数据
const unsigned char *name = sqlite3_column_text(stmt, 0);
int age = sqlite3_column_int(stmt, 1);
NSLog(@"%s, %d", name, age);
}
}
}
SqLite3小结
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); // 字符串数据
6.SqLite3第三方框架FMDB使用小结
FMDB是iOS平台的SQLite数据库框架,FMDB以OC的方式封装了SQLite的C语言API.
FMDB的优点
@1使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
@2对比苹果自带的Core Data框架,更加轻量级和灵活
@3提供了多线程安全的数据库操作方法,有效地防止数据混乱