ios 常用的持久化数据存储方式

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同步设备时会备份该目录

下面是示例代码:

 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]; //数组写入plist
19     [dict writeToFile:fullPath2 atomically:YES];
20     
21     NSLog(@"dict - %@",dict);
22 }
23 
24 /** 读取数据*/
25 - (IBAction)readBtn
26 {
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.偏好设置 -- 存放目录 Library/Preference:

很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能
每个应用都有个NSUserDefaults实例,通过它来存取偏好设置
比如,保存用户名、字体大小、是否自动登录

下面是示例代码

/** 保存数据*/
- (IBAction)save
{
    // 1.利用NSUserDefaults,就能直接访问软件的偏好设置(Library/Preferences)是个单例对象
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    //2.存储数据
    [defaults setObject:@"sd" forKey:@"user"];//其中要保存的数据是setObject:@"sd",@“sd”是数据,forKey:@"user"是以user的键值保存的,
  /**
    key - value 
    @"user" - @"sd" 
  */
[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 - %@ test - %@ age - %d autoLogin - %d ,",user,test,age,autoLogin); }

//下面是解档归档基本OC对象
- (void)test
{

  NSString *mName = @"zhangsan";

 // 获取doc的目录

   NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

    // 拼接保存的路径


    NSString *filePath = [docPath stringByAppendingPathComponent:@"dataList"];


    


    


//    NSData *mData = [mName dataUsingEncoding:NSUTF8StringEncoding];


    


    [NSKeyedArchiver archiveRootObject:mName toFile:filePath];


    


    NSString *testName = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];


    


    NSLog(@"解档出来的数据是 ----- %@",testName);


}


注意: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 @end
10 
11 
12 #import "Person.h"
13 
14 @implementation Person
15 
16 //归档的时候调用
17 /** 将某个对象写入文件的时候会调用,在这个方法中说明哪些对象的哪些属性需要存储*/
18 - (void)encodeWithCoder:(NSCoder *)enCoder
19 {
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 *)decoder
29 {
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 @end
44 
45 
46 #import "SDViewController.h"
47 #import "Person.h"
48 
49 @interface SDViewController ()
50 
51 @end
52 
53 @implementation SDViewController
54 
55 - (void)viewDidLoad
56 {
57     [super viewDidLoad];
58     
59     
60 }
61 
62 - (IBAction)save
63 {
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)read
83 {
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);

 

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提供了多线程安全的数据库操作方法,有效地防止数据混乱

  

 FMDB简单使用示例代码

#import "CZViewController.h"
#import "FMDB.h"

@interface CZViewController ()
- (IBAction)insertBtnClick;
- (IBAction)updateBtnClick;
- (IBAction)deleteBtnClick;
- (IBAction)queryBtnClick;
@property (nonatomic, strong) FMDatabase *db;
@end

@implementation CZViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // 0.获取沙盒路径
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"];
    
    // 1.获得数据库对象
    self.db = [FMDatabase databaseWithPath:fileName];
    
    // 2.打开数据库
    if ([self.db open]) {
        NSLog(@"打开成功");
        // 2.1创建表
       BOOL success =  [self.db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, age INTEGER NOT NULL);"];
        if (success) {
            NSLog(@"创建表成功");
        }else
        {
            NSLog(@"创建表失败");
        }
    }else
    {
        NSLog(@"打开失败");
    }
}

- (IBAction)insertBtnClick
{
    
    for (int i = 0; i < 100; i++) {
        NSString *name = [NSString stringWithFormat:@"Jonathan-%d", i];
        int age = arc4random_uniform(1000);
        
        BOOL success = [self.db executeUpdate:@"INSERT INTO t_student(name , age) VALUES(?, ?);", name, @(age)];// 注意只能拼接对象类型
        if (success) {
            NSLog(@"添加成功");
        }else
        {
            NSLog(@"添加失败");
        }
    }
}

- (IBAction)updateBtnClick
{
    BOOL success = [self.db executeUpdate:@"UPDATE t_student SET name = 'JACK' WHERE age < 50"];
    if (success) {
        NSLog(@"修改成功");
    }else
    {
        NSLog(@"修改失败");
    }

}
- (IBAction)deleteBtnClick
{
    BOOL success = [self.db executeUpdate:@"DELETE FROM t_student WHERE age < ?;", @50];
    if (success) {
        NSLog(@"删除成功");
    }else
    {
        NSLog(@"删除失败");
    }

}
- (IBAction)queryBtnClick
{
    // 1.查询
//    FMResultSet *set = [self.db  executeQuery:@"SELECT id, name, age FROM t_student;"];
    FMResultSet *set = [self.db  executeQuery:@"SELECT * FROM t_student;"];
    
    // 2.取出数据
    while ([set next]) {
        
        // 取出姓名
//       NSString *name = [set stringForColumnIndex:1];
        // 取出年龄
//       int age = [set intForColumnIndex:2];
        NSString *name = [set stringForColumn:@"name"];
        int age = [set intForColumn:@"age"];
        NSLog(@"name = %@, age = %d", name, age);
    }
}
@end

FMDB线程安全

#import "CZViewController.h"
#import "FMDB.h"

@interface CZViewController ()
- (IBAction)insertBtnClick;
- (IBAction)updateBtnClick;
- (IBAction)deleteBtnClick;
- (IBAction)queryBtnClick;
@property (nonatomic, strong) FMDatabase *db;
@property (nonatomic, strong) FMDatabaseQueue *queue;
@end

@implementation CZViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // 0.获取沙盒路径
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    NSString *fileName = [path stringByAppendingPathComponent:@"t_student.sqlite"];
    
    // 1.获得数据库对象
//    self.db = [FMDatabase databaseWithPath:fileName];
    // 1.活的数据库队列对象
    self.queue = [FMDatabaseQueue databaseQueueWithPath:fileName];
    
    // 2.在数据库队列中执行线程安全的操作
    [self.queue inDatabase:^(FMDatabase *db) {
        if ([db open]) {
            // 2.1创建表
            BOOL success =  [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_person (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, money INTEGER NOT NULL);"];
            if (success) {
                NSLog(@"创建表成功");
            }else
            {
                NSLog(@"创建表失败");
            }
        }

    }];

}

- (IBAction)insertBtnClick
{
    [self.queue inDatabase:^(FMDatabase *db) {
        [db executeUpdate:@"INSERT INTO t_person(name, money) VALUES('Zs', 1000)"];
        [db executeUpdate:@"INSERT INTO t_person(name, money) VALUES('LS', 1000)"];
    }];
}

- (IBAction)updateBtnClick
{
    /*
    [self.queue inDatabase:^(FMDatabase *db) {
        [db beginTransaction]; // 开启事务
        [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"];
//        [db rollback];// 主动回滚
        [db executeUpdate:@"update t_person set money = 2000 where name = 'LS';"];
        [db commit];// 提交事务
    }];
     */
    
    [self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
         [db executeUpdate:@"update t_person set money = 0 where name = 'Zs';"];
        NSLog(@"主动回滚");
        *rollback = YES;
         [db executeUpdate:@"update t_person set money = 2000 where name = 'LS';"];
    }];

}
- (IBAction)deleteBtnClick
{
   [self.queue inDatabase:^(FMDatabase *db) {
       BOOL success = [db executeUpdate:@"DELETE FROM t_student WHERE age < ?;", @50];
       if (success) {
           NSLog(@"删除成功");
       }else
       {
           NSLog(@"删除失败");
       }
   }];

}
- (IBAction)queryBtnClick
{
    [self.queue inDatabase:^(FMDatabase *db) {
        // 1.查询
        FMResultSet *set = [db  executeQuery:@"SELECT * FROM t_student;"];
        
        // 2.取出数据
        while ([set next]) {
            NSString *name = [set stringForColumn:@"name"];
            int age = [set intForColumn:@"age"];
            NSLog(@"name = %@, age = %d", name, age);
        }
    }];

}
@end

 
原文地址:https://www.cnblogs.com/ndyBlog/p/3962509.html