核心思想:存儲的Key 經過MD5加密,將NSDictionary;NSArray;NSString;NSData轉換為NSString 存儲為text格式,同時將數據類型寫入數據表;讀取時,根據儲存的數據類型還原即可;
上代碼:
先來看一眼API:
/**
* 更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @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;
/**
* 強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @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;
/**
* 更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @param key 以url的host,soureUrl,參數列表,拼接之后MD5作為Key
* @param cacheData cacheData
* @param cacheSeconds 緩存有效期
*/
-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @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 基本使用方法:
創(chuàng)建數據庫
-(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)
/**
* 更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @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;
/**
* 強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @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;
/**
* 更新緩存數據,則在緩存有效期過后更新緩存;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @param key 以url的host,soureUrl,參數列表,拼接之后MD5作為Key
* @param cacheData cacheData
* @param cacheSeconds 緩存有效期
*/
-(void)updataCacheWithKey:(NSString *)key cacheData:(id) cacheData cacheValidTime:(NSInteger)cacheSeconds;
/**
* 強制更新緩存數據;(如果沒數據則創(chuàng)建,如果有數據則更新)
*
* @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 - 創(chuàng)建數據庫和表
-(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]] ;
//根據緩存是否存在,執(zhí)行更新還是插入;
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;
//根據緩存是否存在,執(zhí)行更新還是插入;
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