欢迎大家关注我的公众号,我会定期分享一些我在项目中遇到问题的解决办法和一些iOS实用的技巧,现阶段主要是整理出一些基础的知识记录下来
文章也会同步更新到我的博客:
ppsheep.com
sqlite几乎在每个APP编码都会涉及到,它是一种轻量级的数据库,在手机端使用起来极其方便,因为SQLite原生的接口都是使用C写的,不是特别友好,所有有一个强大库就出现了FMDB,今天我们基于FMDB来进行二次封装
项目结构
首先来看一下我的项目结构
封装思路
数据层的基本封装思路是:
- 首先我们需要一个数据库管理类,这个管理类主要是管理数据库文件,因为我们可能会有很多个数据库文件,需要这样一个管理类
- 一个基础的BaseDBStore,其中主要是我们需要执行的一些基本的操作,包括增、删、改、查,然后每个模块需要使用到数据库的时候,他们有单独的子模块,是从Base继承而来
数据库管理类的实现代码:
#import
#import "FMDB.h"
@interface PPSDBManager : NSObject
/**
* DB队列 还可以定义其他的数据库 这里只是一个示例
*/
@property (nonatomic, strong) FMDatabaseQueue *commonQueue;
+ (PPSDBManager *)sharedInstance;
/**
创建数据库文件
@param userId 传入用户id
@return 数据库文件地址
*/
+ (NSString *)dbPath:(NSString *)userId;
@end
这里加入了用户思想,即每个用户是一个数据库文件,这样好区分,而且每个用户可以拥有不同的数据库文件,这里只创建了一个,当然还可以创建很多个
#import "PPSDBManager.h"
static PPSDBManager *manager;
@implementation PPSDBManager
+(PPSDBManager *)sharedInstance{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *userID = @"ppsheep";//随便写了一个id
manager = [[PPSDBManager alloc] initWithUserId:userID];
});
return manager;
}
/**
一般的,如果有用户的APP,这里就可以传入当前用户的id 用以区分数据库
这里我就随便写了
@param userId 用户id
@return 实例
*/
- (instancetype)initWithUserId:(NSString *)userId{
if (self = [super init]) {
NSString *commonQueuePath = [PPSDBManager dbPath:userId];
self.commonQueue = [FMDatabaseQueue databaseQueueWithPath:commonQueuePath];
}
return self;
}
/**
数据库文件地址
@return 地址
*/
+ (NSString *)dbPath: (NSString *)userId{
NSString *path = [NSString stringWithFormat:@"%@/User/%@/Setting/DB/", NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0], userId];
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
//创建数据库文件
NSError *error;
[[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
if (error) {
NSLog(@"创建数据库文件失败:%@",path);
}
}
return [path stringByAppendingString:@"common.sqlite3"];
}
@end
BaseStore
#import
#import "PPSDBManager.h"
@interface PPSDBBaseStore : NSObject
// 数据库操作队列(从NADBManager中获取,默认使用commonQueue)
@property (nonatomic, weak) FMDatabaseQueue *dbQueue;
/**
* 表创建
*/
- (BOOL)createTable:(NSString*)tableName withSQL:(NSString*)sqlString;
/*
* 执行带数组参数的sql语句 (增,删,改)
*/
-(BOOL)excuteSQL:(NSString*)sqlString withArrParameter:(NSArray*)arrParameter;
/*
* 执行带字典参数的sql语句 (增,删,改)
*/
-(BOOL)excuteSQL:(NSString*)sqlString withDicParameter:(NSDictionary*)dicParameter;
/*
* 执行格式化的sql语句 (增,删,改)
*/
- (BOOL)excuteSQL:(NSString *)sqlString,...;
/**
* 执行查询指令
*/
- (void)excuteQuerySQL:(NSString*)sqlStr resultBlock:(void (^)(FMResultSet * rsSet))resultBlock;
@end
Base定义的一些基础的操作,注释都写的很清楚,我就不一一解释了
//查询语句
- (BOOL)excuteSQL:(NSString *)sqlString,...
{
__block BOOL ok = NO;
if (self.dbQueue) {
va_list args;
va_list *p_args;
p_args = &args;
va_start(args, sqlString);
[self.dbQueue inDatabase:^(FMDatabase *db) {
ok = [db executeUpdate:sqlString withVAList:*p_args];
}];
va_end(args);
}
return ok;
}
带参数的查询方法:
- (BOOL)excuteSQL:(NSString *)sqlString withArrParameter:(NSArray *)arrParameter
{
__block BOOL ok = NO;
if (self.dbQueue) {
[self.dbQueue inDatabase:^(FMDatabase *db) {
ok = [db executeUpdate:sqlString withArgumentsInArray:arrParameter];
}];
}
return ok;
}
Base里面的方法,都是调用FMDB
User模块
现在,我们有一个User模块,需要实现用户的存取,首先,我们需要一个装SQL的文件,分离SQL
PPSDBUserSQL.h
#ifndef PPSDBUserSQL_h
#define PPSDBUserSQL_h
#define USER_TABLE_NAME @"user"
/**
* 建表
*
* @param uid 当前用户Corp邮箱前缀
* @param fid 好友Corp邮箱前缀
* @param email Corp邮箱
*
* @return
*/
#define SQL_CREATE_USER_TABLE
@"CREATE TABLE IF NOT EXISTS %@(\
uid TEXT,\
name TEXT,\
email TEXT,\
phoneNum TEXT,\
ext1 TEXT,\
ext2 TEXT,\
ext3 TEXT,\
ext4 INTEGER DEFAULT (0),\
ext5 INTEGER DEFAULT (0),\
ext6 INTEGER DEFAULT (0),\
PRIMARY KEY(uid))"
#define SQL_ADD_USER @"INSERT OR REPLACE INTO %@ ( uid, name, email, phoneNum, ext1, ext2, ext3, ext4, ext5, ext6) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
#define SQL_SELECT_USER @"SELECT * FROM %@ WHERE uid = '%@'"
#define SQL_GET_ALL_USER @"SELECT * FROM %@ "
#define SQL_DELETE_USER @"DELETE FROM %@ WHERE uid = '%@'"
#define SQL_UPDATE_USER @"UPDATE %@ SET name = ?, email = ?, phoneNum = ? WHERE uid = '%@' "
#endif /* PPSDBUserSQL_h */
然后是具体的操作User的Store 包含了基本的
#import "PPSDBBaseStore.h"
@class PPSUser;
@interface PPSDBUserStore : PPSDBBaseStore
//改
- (BOOL)updateUserData:(NSArray *)users;
//增
- (BOOL)addUser:(NSArray *)users;
//查
- (NSMutableArray *)usersByUserIds:(NSArray *)userIds;
//删
- (BOOL)deleteUserByUid:(NSArray *)userIds;
- (NSArray *)allUsers;
@end
批量查询用户,传入id数组
-(NSMutableArray *)usersByUserIds:(NSArray *)userIds{
NSArray *ids = [userIds copy];
__block NSMutableArray *data = [[NSMutableArray alloc] init];
for (NSString *userId in ids) {
NSString *sqlString = [NSString stringWithFormat:SQL_SELECT_USER, USER_TABLE_NAME, userId];
[self excuteQuerySQL:sqlString resultBlock:^(FMResultSet *retSet) {
while ([retSet next]) {
NSDictionary *dic = @{
@"userId" : [retSet stringForColumn:@"uid"],
@"email" : [retSet stringForColumn:@"email"],
@"name" : [retSet stringForColumn:@"name"],
@"phoneNum" : [retSet stringForColumn:@"phoneNum"],
};
PPSUser *user = [[PPSUser alloc] initWithDic:dic];
[data addObject:user];
}
[retSet close];
}];
}
return data;
}
批量更新用户,传入用户数组
-(BOOL)updateUserData:(NSArray *)users{
NSArray *userCopy = [users copy];
BOOL ok = YES;
for (PPSUser *user in userCopy) {
NSString *sql = [NSString stringWithFormat:SQL_UPDATE_USER, USER_TABLE_NAME, user.userId];
NSArray *arrPara = [NSArray arrayWithObjects:
PPSNoNilString(user.name),
PPSNoNilString(user.email),
PPSNoNilString(user.phoneNum),
@"", @"", @"", @0, @0, @0, nil];
ok = [self excuteSQL:sql withArrParameter:arrPara];
}
return ok;
}
使用
为了方便,我就直接在ViewController中写了,在真正的开发中,一般都会在管理类中进行数据库操作
懒加载一个用户数据库
-(PPSDBUserStore *)store{
if (!_store) {
_store = [[PPSDBUserStore alloc] init];
}
return _store;
}
初始化用户,直接插入
- (void)initUsers{
NSMutableArray *arr = [NSMutableArray array];
for (int i=0; i<10; i++) {
PPSUser *user = [[PPSUser alloc] init];
user.userId = [NSString stringWithFormat:@"%ld_userId",(long)i];
user.name = [NSString stringWithFormat:@"%ld_userName",(long)i];
user.email = [NSString stringWithFormat:@"%ld_email",(long)i];
user.phoneNum = [NSString stringWithFormat:@"%ld_phoneNum",(long)i];
[arr addObject:user];
}
[self.store addUser:arr];
}
我就不再贴代码出来了,项目工程,我放在了