一种简易的客户端存储架构设计
今天看了公司内部某三个APP项目的存储相关代码。总体来说,存储架构基本上是类似的。对此,我绘制了其存储架构的示意图,如下图所示。
数据库
项目使用自定义的数据库KVDBStore
,该数据库实际上只是对开源数据库FMDatabase
进行了封装,其包含如下两个属性。
1 | @interface KVDBStore() |
KVDBStore
存储于应用沙盒的Data Container
中的Documents
目录下(进一步了解应用沙盒结构)。该目录可以通过如下方法获取。
1
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
KVDBStore
数据库的存储条目具有几个特定的值,使用DBItem
对象来表示,其属性包括:
1
2
3
4
5
6
7@interface DBItem : NSObject
@property (strong, nonatomic) NSString * itemId;
@property (strong, nonatomic) id itemObject;
@property (strong, nonatomic) NSDate * createdTime;
@end
KVDBStore
主要提供了构造方法、析构方法以及一些基本的操作方法,如:增删查改、Transaction操作等,如下所示:
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- (id)initDBWithName:(NSString *)dbName;
- (id)initWithDBWithPath:(NSString *)dbPath;
- (BOOL)createTableWithName:(NSString *)tableName;
- (BOOL)clearTable:(NSString *)tableName;
- (void)close;
...
///************************ Transaction methods *************************************
- (BOOL)beginTransaction;
- (BOOL)rollbackTransaction;
- (BOOL)commitTransaction;
...
///************************ Put&Get methods *****************************************
- (BOOL)putObject:(id)object withId:(NSString *)objectId intoTable:(NSString *)tableName;
- (id)getObjectById:(NSString *)objectId fromTable:(NSString *)tableName;
- (BOOL)deleteObjectById:(NSString *)objectId fromTable:(NSString *)tableName;
...
表
KVDBStore
是在数据库层面实现的一个类,一个数据库通常是由多个表组成的,在实际开发中,表间的联结操作相对比较少,主要还是对特定表进行增删查改的操作。对此,项目实现了表级类BaseTable
以便于进行操作,其包含以下属性:
1
2
3
4
5
6
7@interface BaseTable ()
@property (nonatomic, strong) NSString *databaseName;
@property (nonatomic, strong) NSString *tableName;
@property (nonatomic, strong) KVDBStore *databaseStore;
@end
存储架构
项目只实例化了一个数据库,所有的表均建立在该数据库中,并且所有的表都继承自BaseTable
,而这些表则定义了与该表相关的数据库操作。以AccountTable
为例,其应该定义类似以下的方法:
1
2
3
4
5
6
7- (NSString *)getAccount;
- (void)setAccount:(NSString *)account;
- (UserInfo *)userInfo;
- (void)setUserInfo:(UserInfo *)userInfo;
...
在实际开发中,我们经常会面临同时从(向)一个表(或多个表)读取(写入)数据。对此,项目中实现了各种代理单例来完成这些操作,如:使用AccountAgent
定义登录和退出的方法,其内部需要对AccountTable
进行很多复杂的操作,。当然,在涉及到表间联结操作时,也应该通过代理来进行实现。
1
2
3
4
5
6// AccountAgent
- (void)login;
- (void)logout;
...
总结
后续,希望能够阅读以下FMDatabase
的源码,以对iOS底层的存储原理有进一步的理解。
(完)