核心思想:存储的Key 经过MD5加密,将NSDictionary;NSArray;NSString;NSData转换为NSString 存储为text格式,同时将数据类型写入数据表;读取时,根据储存的数据类型还原即可;
上代码:
先来看一眼API:
/**
* 更新缓存数据,则在缓存有效期过后更新缓存;(如果没数据则创建,如果有数据则更新)
*
* @param urlString 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param parameter parameter
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 强制更新缓存数据;(如果没数据则创建,如果有数据则更新)
*
* @param urlString 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param parameter parameter
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)forceUpdataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 更新缓存数据,则在缓存有效期过后更新缓存;(如果没数据则创建,如果有数据则更新)
*
* @param key 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 强制更新缓存数据;(如果没数据则创建,如果有数据则更新)
*
* @param key 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)forceUpdataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 加载缓存数据
*
* @param urlString url
* @param parameter 参数
*
* @return 缓存数据
*/
-(id)loadCacheWithUrl:(NSString *)urlString parameter:(id) parameter;
/**
* 加载缓存数据
*
* @param key 缓存数据库的 key: 内部以KeyMD5作为Key
*
* @return 缓存数据
*/
-(id)loadCacheWithKey:(NSString *)key;
/**
* 清空缓存数据表
*/
-(void)clearDatabaseTable;
核心代码片段:
NSDictionary;NSArray;NSString;NSData转换为NSString,便于写入数据表
- (NSString *)stringWithData:(id )data{
if ([data isKindOfClass:[NSDictionary class]]) { // 数组/字典
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}else if ([data isKindOfClass:[NSArray class]]){
NSArray *array = data;
return [array componentsJoinedByString:@","];
}else if([data isKindOfClass:[NSData class]]){
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}else if([data isKindOfClass:[NSString class]]){
return data;
}else{
NSAssert(NO, @"数据类型不支持,目前只支持: NSDictionary;NSArray;NSString;NSData");
}
return nil;
}
数据读取后还原过程
- (id)dataWithString:(NSString *)string classType:(NSNumber *)classType{
NSInteger type = [classType integerValue];
switch (type) {
case ClassTypeDictionary:{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
}break;
case ClassTypeArray:
return [string componentsSeparatedByString:@","];
break;
case ClassTypeData:
return [string dataUsingEncoding:NSUTF8StringEncoding];
break;
case ClassTypeString:
return string;
break;
default: // ClassTypeOther
return nil;
break;
}
}
以下为FMDB 基本使用方法:
创建数据库
-(void)creatScarchRecodeTable{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains
(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentPath stringByAppendingPathComponent:@"DTDateCache.db"];
_database = [FMDatabase databaseWithPath:path];
NSLog(@"%@",path);
if ([_database open]) {
@try {
[_database executeUpdate:[NSString stringWithFormat:@"create table if not exists DTCacheTable (id integer PRIMARY KEY AUTOINCREMENT, keyName text, creatTime text, validTime text,cacheData text,classType integer)"]];
} @catch (NSException *exception) {
NSAssert(NO, exception.description);
} @finally {
}
}
}
插入数据
-(void)insertDataString:(NSString *)data withKey:(NSString *)key classType:(NSNumber *)classtype{
if (/* DISABLES CODE */ (NO)) {
FMResultSet * result = [_database executeQuery:@"SELECT * FROM table order by time desc LIMIT 1"];
[_database executeUpdate:[NSString stringWithFormat:@"DELETE FROM DTCacheTable WHERE name='%@'",[result stringForColumn:@"recode"]]];
}
[self creatScarchRecodeTable];
NSString *sqlite = [NSString stringWithFormat:@"INSERT INTO DTCacheTable (keyName,creatTime,validTime,cacheData,classType) VALUES (?,?,?,?,?)"];
NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];
BOOL success = [_database executeUpdate:sqlite, key,creatTime,validTime,data,classtype];
NSString *des = [NSString stringWithFormat:@"%@",[_database lastErrorMessage]];
// [_database close];
NSAssert(success, des);
}
更新数据
-(void)updataDataWithKey:(NSString *)key cacheData:(NSString *)cacheData classType:(NSNumber *)classtype{
@try {
[self creatScarchRecodeTable];
NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];
NSString *update = [NSString stringWithFormat:@"UPDATE DTCacheTable SET creatTime = ?, validTime = ?, cacheData = ?, classType = ? WHERE keyName = ? "];
[_database executeUpdate:update,creatTime,validTime,cacheData,classtype,key];
// [_database close];
} @catch (NSException *exception) {
NSAssert(NO, exception.description);
} @finally {
}
}
查询数据
-(NSDictionary *)selectDataFromTableWithKey:(NSString *)key{
FMResultSet * result = [_database executeQuery:[NSString stringWithFormat:@"SELECT * FROM DTCacheTable"]];
while ([result next]) {
if ([key isEqualToString: [result stringForColumn:@"keyName"]]) {
NSNumber *classType = [NSNumber numberWithInt:[result intForColumn:@"classType"]];
NSString *content = [result stringForColumn:@"cacheData"];
return [NSDictionary dictionaryWithObjectsAndKeys:classType,@"classType",content,@"content", nil];
}
}
// [_database close];
return nil;
}
以下是完整代码:
#import <Foundation/Foundation.h>
@interface DTSqliteManager : NSObject
singleTon_h(DTSqliteManager)
/**
* 更新缓存数据,则在缓存有效期过后更新缓存;(如果没数据则创建,如果有数据则更新)
*
* @param urlString 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param parameter parameter
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 强制更新缓存数据;(如果没数据则创建,如果有数据则更新)
*
* @param urlString 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param parameter parameter
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)forceUpdataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 更新缓存数据,则在缓存有效期过后更新缓存;(如果没数据则创建,如果有数据则更新)
*
* @param key 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 强制更新缓存数据;(如果没数据则创建,如果有数据则更新)
*
* @param key 以url的host,soureUrl,参数列表,拼接之后MD5作为Key
* @param cacheData cacheData
* @param cacheSeconds 缓存有效期
*/
-(void)forceUpdataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 加载缓存数据
*
* @param urlString url
* @param parameter 参数
*
* @return 缓存数据
*/
-(id)loadCacheWithUrl:(NSString *)urlString parameter:(id) parameter;
/**
* 加载缓存数据
*
* @param key 缓存数据库的 key: 内部以KeyMD5作为Key
*
* @return 缓存数据
*/
-(id)loadCacheWithKey:(NSString *)key;
/**
* 清空缓存数据表
*/
-(void)clearDatabaseTable;
@end
#import "DTSqliteManager.h"
#import <FMDB/FMDB.h>
#import <sqlite3.h>
#import <CommonCrypto/CommonDigest.h>
//#import "sys/utsname.h"
typedef NS_ENUM(NSUInteger, ClassType) {
ClassTypeDictionary = 1 << 0,
ClassTypeArray = 1 << 1,
ClassTypeString = 1 << 2,
ClassTypeData = 1 << 3,
ClassTypeOther = 1 << 4
};
@interface DTSqliteManager()
@end
@implementation DTSqliteManager{
FMDatabase *_database;
NSInteger _cacheValidTime;
}
singleTon_m(DTSqliteManager)
#pragma mark - 创建数据库和表
-(void)creatScarchRecodeTable{
NSString *documentPath = [NSSearchPathForDirectoriesInDomains
(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentPath stringByAppendingPathComponent:@"DTDateCache.db"];
_database = [FMDatabase databaseWithPath:path];
NSLog(@"%@",path);
if ([_database open]) {
@try {
[_database executeUpdate:[NSString stringWithFormat:@"create table if not exists DTCacheTable (id integer PRIMARY KEY AUTOINCREMENT, keyName text, creatTime text, validTime text,cacheData text,classType integer)"]];
} @catch (NSException *exception) {
NSAssert(NO, exception.description);
} @finally {
}
}
}
#pragma mark - 缓存数据库-插入数据
-(void)insertDataString:(NSString *)data withKey:(NSString *)key classType:(NSNumber *)classtype{
if (/* DISABLES CODE */ (NO)) {
FMResultSet * result = [_database executeQuery:@"SELECT * FROM table order by time desc LIMIT 1"];
[_database executeUpdate:[NSString stringWithFormat:@"DELETE FROM DTCacheTable WHERE name='%@'",[result stringForColumn:@"recode"]]];
}
[self creatScarchRecodeTable];
NSString *sqlite = [NSString stringWithFormat:@"INSERT INTO DTCacheTable (keyName,creatTime,validTime,cacheData,classType) VALUES (?,?,?,?,?)"];
NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];
BOOL success = [_database executeUpdate:sqlite, key,creatTime,validTime,data,classtype];
NSString *des = [NSString stringWithFormat:@"%@",[_database lastErrorMessage]];
// [_database close];
NSAssert(success, des);
}
-(void)updataDataWithKey:(NSString *)key cacheData:(NSString *)cacheData classType:(NSNumber *)classtype{
@try {
[self creatScarchRecodeTable];
NSString *creatTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000)];
NSString *validTime = [NSString stringWithFormat:@"%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000) + _cacheValidTime];
NSString *update = [NSString stringWithFormat:@"UPDATE DTCacheTable SET creatTime = ?, validTime = ?, cacheData = ?, classType = ? WHERE keyName = ? "];
[_database executeUpdate:update,creatTime,validTime,cacheData,classtype,key];
// [_database close];
} @catch (NSException *exception) {
NSAssert(NO, exception.description);
} @finally {
}
}
#pragma mark - 缓存数据库-查询数据
-(NSDictionary *)selectDataFromTableWithKey:(NSString *)key{
FMResultSet * result = [_database executeQuery:[NSString stringWithFormat:@"SELECT * FROM DTCacheTable"]];
while ([result next]) {
if ([key isEqualToString: [result stringForColumn:@"keyName"]]) {
NSNumber *classType = [NSNumber numberWithInt:[result intForColumn:@"classType"]];
NSString *content = [result stringForColumn:@"cacheData"];
return [NSDictionary dictionaryWithObjectsAndKeys:classType,@"classType",content,@"content", nil];
}
}
// [_database close];
return nil;
}
#pragma mark - 清空缓存数据库
-(void)clearDatabaseTable{
BOOL success = [_database executeUpdate:[NSString stringWithFormat:@"DELETE FROM DTCacheTable"]];
NSString *des = [NSString stringWithFormat:@"%@",[_database lastErrorMessage]];
NSAssert(success, des);
}
#pragma mark - 数据库表名
//-(NSString *)getDatabaseTableName{
// return [@"DTCache" dt_Md5Str];
//}
-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds forceUpdata:(BOOL)force{
_cacheValidTime = cacheSeconds;
NSString * key_MD5 =[self stringToMD5String:[NSString stringWithFormat:@"%@%@",urlString,parameter]] ;
//根据缓存是否存在,执行更新还是插入;
if ([self hasCacheWiWithKey:key_MD5]) {
if (force) {
// 更新
[self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];
}else{
if ([self cacheTimeOutWithKey:key_MD5]) {
[self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];
}
}
}else{
// 插入
[self insertDataString:[self stringWithData:cacheData] withKey:key_MD5 classType:[self classTypeWithData:cacheData]];
}
}
-(void)updataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
[self updataCacheWithUrl:urlString parameter:parameter cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:NO];
}
-(void)forceUpdataCacheWithUrl:(NSString *)urlString parameter:(id) parameter cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
[self updataCacheWithUrl:urlString parameter:parameter cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:NO];
}
-(BOOL)hasCacheWiWithKey:(NSString *)key{
return [self selectDataFromTableWithKey:key] ? YES:NO;
}
-(BOOL)cacheTimeOutWithKey:(NSString *)key{
FMResultSet * result = [_database executeQuery:[NSString stringWithFormat:@"SELECT * FROM DTCacheTable"]];
while ([result next]) {
if ([key isEqualToString:[result stringForColumn:@"keyName"]]) {
NSLog(@"+++++%f",[[result stringForColumn:@"validTime"] doubleValue]);
NSLog(@"缓存有效期%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000));
NSLog(@"当前时间:%ld",(long)(kCFAbsoluteTimeIntervalSince1970 / 1000));
return [[result stringForColumn:@"validTime"] intValue] > (int)(kCFAbsoluteTimeIntervalSince1970 / 1000) ? NO:YES;
}
}
return YES;
}
-(void)updataCacheWithKey:(NSString *)key cacheData:(id)cacheData cacheValidTime:(NSInteger)cacheSeconds forceUpdata:(BOOL)force{
NSString* key_MD5 = [self stringToMD5String:key];
_cacheValidTime = cacheSeconds;
//根据缓存是否存在,执行更新还是插入;
if ([self hasCacheWiWithKey:key_MD5]) {
if (force) {
// 更新
[self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];
}else{
if ([self cacheTimeOutWithKey:key_MD5]) {
// 更新
[self updataDataWithKey:key_MD5 cacheData: [self stringWithData:cacheData] classType:[self classTypeWithData:cacheData]];
}
}
}else{
// 插入
[self insertDataString:[self stringWithData:cacheData] withKey:key_MD5 classType:[self classTypeWithData:cacheData]];
}
}
-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
[self updataCacheWithKey:key cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:NO];
}
-(void)forceUpdataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;{
[self updataCacheWithKey:key cacheData:cacheData cacheValidTime:cacheSeconds forceUpdata:YES];
}
-(id)loadCacheWithUrl:(NSString *)urlString parameter:(id) parameter;{
NSString *key_MD5 = [self stringToMD5String:[NSString stringWithFormat:@"%@%@",urlString,parameter]];
if ([self hasCacheWiWithKey:key_MD5]) {
NSDictionary *diction = [self selectDataFromTableWithKey:key_MD5];
return [self dataWithString:[diction objectForKey:@"content"] classType:[diction objectForKey:@"classType"]];
}
return nil;
}
-(id)loadCacheWithKey:(NSString *)key{
NSString *key_MD5 = [self stringToMD5String:key];
if ([self hasCacheWiWithKey:key_MD5]) {
NSDictionary *diction = [self selectDataFromTableWithKey:key_MD5];
return [self dataWithString:[diction objectForKey:@"content"] classType:[diction objectForKey:@"classType"]];
}
return nil;
}
-(NSString *)stringToMD5String:(NSString *)string;{
const char *cStr = [string UTF8String];
unsigned char result[16];
CC_MD5(cStr, (CC_LONG)strlen(cStr), result); // This is the md5 call
return [NSString stringWithFormat:
@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
];
}
- (id)dataWithString:(NSString *)string classType:(NSNumber *)classType{
NSInteger type = [classType integerValue];
switch (type) {
case ClassTypeDictionary:{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
}break;
case ClassTypeArray:
return [string componentsSeparatedByString:@","];
break;
case ClassTypeData:
return [string dataUsingEncoding:NSUTF8StringEncoding];
break;
case ClassTypeString:
return string;
break;
default: // ClassTypeOther
return nil;
break;
}
}
- (NSString *)stringWithData:(id )data{
if ([data isKindOfClass:[NSDictionary class]]) { // 数组/字典
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}else if ([data isKindOfClass:[NSArray class]]){
NSArray *array = data;
return [array componentsJoinedByString:@","];
}else if([data isKindOfClass:[NSData class]]){
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}else if([data isKindOfClass:[NSString class]]){
return data;
}else{
NSAssert(NO, @"数据类型不支持,目前只支持: NSDictionary;NSArray;NSString;NSData");
}
return nil;
}
-(NSNumber *)classTypeWithData:(id)data{
if ([data isKindOfClass:[NSArray class]]) {
return [NSNumber numberWithInteger:ClassTypeArray];
}else if ([data isKindOfClass:[NSDictionary class]]){
return [NSNumber numberWithInteger:ClassTypeDictionary];
}else if ([data isKindOfClass:[NSString class]]){
return [NSNumber numberWithInteger:ClassTypeString];
}else if ([data isKindOfClass:[NSData class]]){
return [NSNumber numberWithInteger:ClassTypeData];
}else{
return [NSNumber numberWithInteger:ClassTypeOther];
}
}
@end