iOS CraziesiOS学习iOS开发

基于FMDB构建网络缓存

2017-02-08  本文已影响33人  hehtao

核心思想:存储的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

上一篇下一篇

猜你喜欢

热点阅读