相比于服务器端的数据存储,IOS中几种数据存储的技术:
(1)XML属性列表 —— PList
(2)NSKeyedArchiver 归档
(3)Preference(偏好设置)
(4)SQLite3
(5)Core Data(以面向对象的方式操作数据库SQLite)
发现用数据库进行数据的存储和缓存,才是王道,
比较有心得的体会:虽然通过文件的方式进行存储,读写速度相对数据库存储较快,但是涉及大批量的数据时,在查询/管理/优化方面,数据库的优势明显会更大些.而且作为移动端,SQLite数据库在数据缓存方面的运用则尤为重要.
工作之余,运用SQLite3的许多小知识点,写了一个小小的数据库增删改查操作,专门与sqlite3交互的个人信息管理类,直接上代码,望大牛指正:
底层架构图
核心代码实现:
(1) Services服务层封装
PesonManager.h
#import <Foundation/Foundation.h> #import "Person.h" @interface PersonManager : NSObject + (instancetype)sharedPersonManager; // 1. 新增用户 - (void)addPerson:(Person *)person; // 2. 更新用户(关于主键,永远都不要去修改) - (void)updatePerson:(Person *)person; // 3. 删除用户,使用主键来删除指定用户 - (void)removePerson:(NSInteger)personID; // 4. 列表用户,查询所有用户 - (NSArray *)allPersons; @end
PesonManager.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
#import "PersonManager.h" #import <sqlite3.h> #import "NSString+JH.h" // 全局变量 static PersonManager *_instance;
@interface
PersonManager()
{ // 全局的数据库句柄
sqlite3 *_db;
} @end @implementation
PersonManager
#pragma mark - 单例的方法 + ( id )allocWithZone:( struct
_NSZone *)zone
{ static
dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [ super
allocWithZone:zone];
});
return
_instance;
} + (instancetype)sharedPersonManager { if
(_instance == nil ) {
_instance = [[PersonManager alloc] init];
}
return
_instance;
} #pragma mark - 类方法 - ( id )init
{ self
= [ super
init];
// 懒加载数据库连接及创建数据表
if
( self ) {
// 1. 打开数据库
[ self
openDB];
// 2. 创建数据表
[ self
createTable];
}
return
self ;
} #pragma mark 打开数据库 - ( void )openDB
{ NSString
*dbPath = [@ "T_Person.db"
appendDocumentDir];
_db = NULL ;
if
(SQLITE_OK == sqlite3_open([dbPath UTF8String], &_db)) {
NSLog (@ "数据库打开成功" );
} else
{
NSLog (@ "数据库打开失败" );
}
} #pragma mark 单步执行SQL - ( void )execSQL:( NSString
*)sql message:( NSString
*)message
{ char
*errmsg = NULL ;
if
(SQLITE_OK == sqlite3_exec(_db, [sql UTF8String], NULL , NULL , &errmsg)) {
NSLog (@ "%@成功!" , message);
} else
{
NSLog (@ "%@失败 - %s" , message, errmsg);
}
} #pragma mark 创建数据表 - ( void )createTable
{ NSString
*sql = @ "CREATE TABLE IF NOT EXISTS T_Person (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT, gender INTEGER, age INTEGER, height REAL)" ;
[ self
execSQL:sql message:@ "创建数据表" ];
} - ( void )addPerson:(Person *)person
{<br> // 1. SQL
NSString
*sql = [ NSString
stringWithFormat:@ "INSERT INTO T_Person (name, gender, age, height) VALUES (‘%@‘, %d, %d, %f)" , person.name, person.gender, person.age, person.height];
[ self
execSQL:sql message:@ "新增个人记录" ];
} // 2. 更新用户(关于主键,永远都不要去修改) - ( void )updatePerson:(Person *)person where: ( NSStirng
*)where
{ NSString
*sql = [ NSString
stringWithFormat:@ "UPDATE T_Person SET name = ‘%@‘, gender = %d, age = %d, height = %f where %@" , person.name, person.gender, person.age, person.height , where];
[ self
execSQL:sql message:@ "更新个人记录" ];
} // 3. 删除用户,使用主键来删除指定用户 - ( void )removePerson:( NSInteger )personID
{ NSString
*sql =[ NSString
stringWithFormat: @ "delete * from T_Person where id =%@" ,personID];
[ self
execSQL:sql message:@ "删除记录成功" ];
} // 4. 列表用户,查询所有用户 - ( NSArray
*)allPersons
{ NSString
*sql = @ "SELECT id, name, age, gender, height FROM T_Person ORDER BY name" ;
sqlite3_stmt *stmt = NULL ;
NSMutableArray
*arrayM = [ NSMutableArray
array];
NSMutableArray
*persons = nil ;
if
(SQLITE_OK == sqlite3_prepare_v2(_db, [sql UTF8String], -1, &stmt, NULL )) {
persons = [ NSMutableArray
array];
while
(SQLITE_ROW == sqlite3_step(stmt)) {
int
ID = sqlite3_column_int(stmt, 0);
const
unsigned char
*name = sqlite3_column_text(stmt, 1);
int
age = sqlite3_column_int(stmt, 2);
int
gender = sqlite3_column_int(stmt, 3);
CGFloat height = sqlite3_column_double(stmt, 4);
// const unsigned char *直接输出看不出结果,需要转换
NSString
*nameUTF8 = [ NSString
stringWithUTF8String:( const
char *)name];
Person *p = [Person personWithID:ID name:nameUTF8 age:age gender:gender height:height];
[persons addObject:p];
}
} else
{
NSLog (@ "语法错误" );
}
return
persons;
} @end |
接下来在控制器里面封装模型取出相应数据即可,关于SQLite3中运用的知识点,总结如下:
1. sqlite3_open 打开数据库 * 如果数据库已经存在,直接打开 * 如果数据库不存在,新建一个空白的数据库(0KB),然后再打开 2. 创建数据表 * 定义数据操作SQL * 调用sqlite3_exec执行SQL 提示:为了避免重复建表,可以在建表SQL中增加 IF NOT EXISTS 3. 单步执行操作 增/删/改/查数据 4. 查询语句 1> 准备SQL 2> 检查SQL语句是否正确 sqlite3_prepare_v2 3> 单步执行,依次获取查询到的记录 SQLITE_ROW == sqlite3_step... 4> 按照查询顺序,依次取出每一个字段的内容 sqlite3_column_text 取字符串 sqlite3_column_int 取整数 sqlite3_column_double 取浮点数 5.操作SQLite数据库需要5个方法 sqlite3_open sqlite3_exec sqlite3_prepare_v2 sqlite3_step sqlite3_column_text 取字符串 sqlite3_column_int 取整数 sqlite3_column_double 取浮点数 两个枚举 SQLITE_OK SQLITE_ROW
当然,一般在实际开发中都会直接封装成一套数据库操作类,但是对于SQL结构化查询,无论是服务器开发,还是客户端开发,都是万变不离其中.