标签:
对于IOS开发者而言, 项目中数据的本地化存储,最难的一点,莫过于SQL语句的编写,除此之外, 其实也没什么难度, 当然在创建数据库之前,我们必须要做的是对数据进行分析, 然后对FMDB进行简单的封装:
代码如下:
#import "SQLiteManger.h"
#import "FMDB.h"
@interface SQLiteManger ()
@end
@implementation SQLiteManger
/// 创建一个单例单例
+(instancetype)shareSQLiteManger{
static id instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
// 重写init
-(instancetype)init{
// 数据路路径
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
path = [path stringByAppendingPathComponent:@"meifangwang.db"];
NSLog(@"路径是:%@",path);
// 打开数据库,没有则创建一个数据库
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:path];
self.queue = queue;
[self creatTable];
return self;
}
//建表
-(void)creatTable {
// SQL执行语句路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"db.sql" ofType:nil];
NSString *sql = [NSString stringWithContentsOfFile:path];
// 执行SQL语句
[self.queue inDatabase:^(FMDatabase *db) {
if ([db executeStatements:sql]){
NSLog(@"建表成功");
}else{
NSLog(@"建表失败");
}
}];
}
// 查询
-(NSMutableArray *)execRecordSet:(NSString *)sql{
// 定义一个数组
NSMutableArray * array = [[NSMutableArray alloc ] init];
// `同步`执行数据库查询 - FMDB 默认情况下,都是在主线程上执行的
[[SQLiteManger shareSQLiteManger].queue inDatabase:^(FMDatabase *db) {
FMResultSet *rs = [db executeQuery:sql];
while ([rs next]) {
//列数
int colCount = rs.columnCount;
//字典
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
// 遍历
for (int i = 0; i < colCount; i++) {
// 列名
NSString *name = [rs columnNameForIndex:i];
// 值
NSObject * obj = [rs objectForColumnIndex:i];
// 设置字典
dict[name] = obj;
}
[array addObject:dict];
}
}];
return array;
}
@end
相关SQL语句 --> 当然我们建表的SQL语句个人建议单独写在一个文件夹中
CREATE TABLE IF NOT EXISTS "T_Showroom" (
"houseId" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"hourseInfo" TEXT,
"userId" INTEGER
);
1.进行数据结构(数据表)的设计,
eg: 1> 主键的标示
2> 对应房子的完整的数据
3> 当前登陆账户的userId
2. 数据访问层模型的设计
数据访问层(DAL):专门负责处理本地SQLite和网络数据查看本地是否有数据, 有, 直接返回数据, 没有网络中加载
1>加载相关数据 --- > 根据工作需要做适当的调整
1>> 检查本地是否缓存数据
2>> 如果有返回数据
3>> 如果没有,加载网络数据
4>> 将网络返回的数据,保存在本地,一边后续使用
5>> 返回网络数据
2> 保存网络数据(saveCacheData) —> 上面调用
1> 参数
定义一个数据array 记录网络返回的字典数组
2> 编写SQL语句, 根据SQL语句确认参数, _houseId, 网络数据序列化,用户ID
3> 获取要插入数据库的数据:_houseId,用户ID 网络数据序列化(序列化字典 —> 二进制数据)
4> 执行SQL语句, 插入
3> 检查本地是否已有数据—> 1中调用
1> 参数:
2> 编写SQL,并测试SQL
3> 执行SQL语句, 返回数据集合
4> 整合本地缓存数据和网络数据方法
5> 满足一定条件时,清除缓存
1>> 清理缓存工作,千万不要交给用户使用!
2>> 一定要定期清理数据库的缓存,原因
- SQLite 的数据库,随着数据的增加,会不断的变大
- 但是:如果删除了数据,数据库不会变小!SQLite 认为,既然数据库会涨到这么大,留出空间,准备下一次涨到这么大
- SQLite不会再额外分配磁盘空间
- 一般不会把 图片/音频/视频 放在数据库中,不便于检索,占用磁盘空间很大!
eg: swift版定期清除本地数据:
/// 最大缓存时间
private let maxCacheDateTime: NSTimeInterval = 60 // 7 * 24 * 60 * 60
class func clearDataCache() {
// 1. 准备日期
let date = NSDate(timeIntervalSinceNow: -maxCacheDateTime)
// 日期格式转换
let df = NSDateFormatter()
// 指定区域 - 在模拟器不需要,但是真机一定需要
df.locale = NSLocale(localeIdentifier: "en")
// 指定日期格式
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
// 获取日期结果
let dateStr = df.stringFromDate(date)
// 2. 执行 SQL
// 提示:开发调试 删除 SQL 的时候,一定先写 `SELECT *`,确认无误之后,再替换成 `DELETE`
SQLiteManager.sharedManager.queue.inDatabase { (db) -> Void in
if db.executeUpdate(sql, dateStr) {
print("删除了 \(db.changes()) 条缓存数据")
}
}
}
eg: DAL实例:
// 专门负责处理本地SQLite和网络数据
#import "HourseInfoDAL.h"
#import "DataDefine.h"
#import "SQLiteManger.h"
#import "ImageURLsDAO.h"
@class HouseListInfo;
@interface HourseInfoDAL ()
-(void)saveCacheData:(HouseListInfo *)hourseInfo;
@property (nonatomic, assign) int oldArrayCount;
@property (nonatomic, assign) int newArrayCount;
@end
@implementation HourseInfoDAL
#pragma mark 加载数据
-(void)loadHourseInfo:(HouseListInfo *)hourseInfo{
// 1> 检查本地是否缓存数据
// 2> 如果有返回数据
// 3> 如果没有,加载网络数据
[self saveCacheData:hourseInfo];
// 4> 将网络返回的数据,保存在本地,一边后续使用
// 5> 返回网络数据
}
#pragma mark 保存房子数据
-(void)saveCacheData:(HouseListInfo *)hourseInfo{
// 房子信息
NSString* houseid = hourseInfo.houseid; // 房子ID
NSString* listingCategory = hourseInfo.listingCategory;
NSString* commission = hourseInfo.commission;
NSString* bathrooms = hourseInfo.bathrooms;
NSString* bedrooms = hourseInfo.bedrooms;
NSString* listingStatus = hourseInfo.listingCategory;
NSString* price = hourseInfo.price;
NSString* propertySubType = hourseInfo.propertySubType;
NSString* vadate = hourseInfo.vadate;
NSString* imageURL = hourseInfo.imageURL;
NSString* address = hourseInfo.address;
NSString* moneytype = hourseInfo.moneytype;
NSString* islike = hourseInfo.islike;
NSString* imageSource = hourseInfo.imageSource;
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
// 房子信息添加到字典中
[dict setObject:houseid forKey:@"houseid"];
[dict setObject:listingCategory forKey:@"listingCategory"];
[dict setObject:commission forKey:@"commission"];
[dict setObject:bathrooms forKey:@"bathrooms"];
[dict setObject:bedrooms forKey:@"bedrooms"];
[dict setObject:listingStatus forKey:@"listingStatus"];
[dict setObject:price forKey:@"price"];
[dict setObject:propertySubType forKey:@"propertySubType"];
[dict setObject:vadate forKey:@"vadate"];
[dict setObject:imageURL forKey:@"imageURL"];
[dict setObject:address forKey:@"address"];
[dict setObject:moneytype forKey:@"moneytype"];
[dict setObject:islike forKey:@"islike"];
[dict setObject:imageSource forKey:@"imageSource"];
//是否登陆
if (!g_has_login){
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil message:@"\r\n请先登录" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"立即登录", nil];
alert.tag = 101;
[alert show];
return;
}
NSLog(@"房子信息:%@",dict);
//序列化 --- 房子数据
NSData *json = [NSJSONSerialization dataWithJSONObject:dict options:nil error:nil];
// NSLog(@"json: %@",json);
//SQL
NSString *sql = @"INSERT OR REPLACE INTO T_Showroom (houseId, hourseInfo, userId) VALUES (?, ?, ?);";
SQLiteManger *manger = [SQLiteManger shareSQLiteManger];
[manger.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
if ([db executeUpdate:sql, houseid, json, @"123"]) {
NSLog(@"插入成功");
rollback:false;
return;
}
}];
// 获取房子ID 已获得
// 注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tongzhi:) name:@"userId" object:nil];
NSLog(@"哈哈哈woad ");
}
- (void)tongzhi:(NSNotification *)text{
// NSLog(@"%@",text.userInfo[@"textOne"]);
NSLog(@"-----接收到通知------");
}
//
#pragma mark 保存房子详情的相关数据
-(void)savaDetailCacheData:(NSDictionary *)dict{
// 判断是否登录
if (!g_has_login){
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil message:@"\r\n请先登录" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"立即登录", nil];
alert.tag = 101;
[alert show];
return;
}
// NSLog(@"房子详情的相关数据:%@", dict);
// sql
NSString *sql = @"INSERT OR REPLACE INTO T_HourseDetails (houseId, hourseDetailInfo, userId) VALUES (?, ?, ?);";
// 房子ID
NSDictionary *houseManage = dict[@"houseManage"];
NSString *hourseid = houseManage[@"id"];
//序列化 --- 房子详情数据
NSData *json = [NSJSONSerialization dataWithJSONObject:dict options:nil error:nil];
// NSLog(@"房子详情序列化前:%@", dict);
// NSLog(@"房子详情序列化后:%@",json);
NSDictionary * images = dict[@"imageURLs"];
// 可变数组, 存放iamgeUrls
NSMutableArray * imageUrlsArray = [[NSMutableArray alloc] init];
for (NSDictionary * dict in images) {
NSString * imageUrl = dict[@"imageUrl"];
NSLog(@"%@",imageUrl);
[imageUrlsArray addObject:imageUrl];
}
#pragma mark --- 下载详情界面图片
for (int i = 0; i < imageUrlsArray.count; i++) {
NSURL* url = nil;
NSString* urlstr = [imageUrlsArray objectAtIndex:i];
DLOG(@"urlstr >>>>>: %@",urlstr);
if ([urlstr length] > 4 && [[[urlstr substringToIndex:4] lowercaseString] isEqualToString:@"http"])
{
url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",@"",urlstr]];
DLOG(@"url -->> :%@",url);
}
else
{
url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@",BASEIMAGEURL,urlstr]];
DLOG(@"url ==>> :%@",url);
}
// NSString * image = [NSString stringWithFormat:@"image%d",i];
UIImageView *image = [[UIImageView alloc] init];
// [image sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"fangyuan_cell_yongjin_bg"]];
[image sd_setImageWithURL:url];
}
// 用户ID
SQLiteManger *manger = [SQLiteManger shareSQLiteManger];
[manger.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
if ([db executeUpdate:sql, hourseid, json, @"123"]) {
NSLog(@"插入成功");
rollback:false;
return;
}
}];
}
#pragma mark 检查房子本地数据 --->返回已经收藏的数据
-(NSArray *)checkChacheData {
//SQL
NSString * sql = @"SELECT houseId, hourseInfo, userId FROM T_Showroom \n";
sql = [sql stringByAppendingFormat:@"WHERE userId = 123 \n"];
// 执行sql语句
NSArray * array = [[SQLiteManger shareSQLiteManger] execRecordSet:sql];
NSLog(@"%d",self.arrayCountChange);
// 定义一个bool值比较, 收藏的房子是否变化, (数据的增删)
self.newArrayCount = (int)array.count;
NSLog(@"新值:%d",self.newArrayCount);
NSLog(@"旧值:%d", self.oldArrayCount);
if (self.newArrayCount != self.oldArrayCount) {
self.arrayCountChange = 1;
NSLog(@"不相等");
}else{
self.arrayCountChange = 0;
}
self.oldArrayCount = self.newArrayCount;
NSLog(@"旧值:%d", self.oldArrayCount);
//可变的数据, 存储数据
NSMutableArray *arrayM = [[NSMutableArray alloc] init];
// 便利
for (NSDictionary *dict in array) {
NSData *jsonData = dict[@"hourseInfo"];
NSLog(@"反序列化前:%@", jsonData);
// 反序列化 --> 一条完整数据字典
NSDictionary * result = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:nil];
NSLog(@"反序列化后:%@", result);
[arrayM addObject:result];
}
// 返回结果 - 如果没有查询到数据,会返回一个空的数组
return arrayM;
}
#pragma 检查房子详情本地数据 --->返回已经在本地存在的数据
-(NSArray *) checkHourseDetailChacheData{
//SQL
NSString * sql = @"SELECT houseId, hourseDetailInfo, userId FROM T_HourseDetails \n";
sql = [sql stringByAppendingFormat:@"WHERE userId = 123 \n"];
// 执行sql语句
NSArray * array = [[SQLiteManger shareSQLiteManger] execRecordSet:sql];
//可变的数据, 存储数据
NSMutableArray *arrayM = [[NSMutableArray alloc] init];
// 便利
for (NSDictionary *dict in array) {
NSData *jsonData = dict[@"hourseDetailInfo"];
NSLog(@"反序列化前:%@", jsonData);
// 反序列化 --> 一条完整微博数据字典
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:nil];
NSLog(@"反序列化后:%@", result);
[arrayM addObject:result];
}
// 返回结果 - 如果没有查询到数据,会返回一个空的数组
return arrayM;
}
#pragma mark 满足一定条件时清楚缓存 ---> 程序进入后台时调用
-(void)clearDataCache{
// SQL
NSString *sql = @"DELETE FROM T_Status WHERE ;";
// 执行SQL
SQLiteManger *manger = [SQLiteManger shareSQLiteManger];
[manger.queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:sql];
}];
}
#pragma mark 取消收藏时删除,对应的数据
-(void)deleteDataCache:(NSString *)hourseId{
NSLog(@"hourseId:%@",hourseId );
// SQL
NSString *sql = @"DELETE FROM T_Showroom \n";
sql = [sql stringByAppendingFormat:@"WHERE houseId = %@ \n", hourseId];
// NSLog(@"%@",sql);
// 执行SQL
SQLiteManger *manger = [SQLiteManger shareSQLiteManger];
[manger.queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:sql];
}];
}
@end
标签:
原文地址:http://www.cnblogs.com/LZ-lizhen/p/5058417.html