项目中数据缓存以及FMDB的使用

公司项目是用cocospod管理的第三方库:
podfile文件中加入 pod 'FMDB', '~> 2.6.2'引入FMDB就可以使用了

项目是新闻类的app,只有下拉刷新,缓存的思路:

项目中数据缓存以及FMDB的使用_第1张图片
屏幕快照 2016-09-19 下午6.14.22.png

设计NIPNewsDatabase类来管理数据库文件

  • 保存
  • 查找
  • 删除数据库文件

在保存的时候涉及到清除陈旧的数据,清除的思路:

  • 设定缓存的时间长 maxTime
    添加一个存储时间的字段,删除改频道下一周之前的数据
  • 设定缓存的新闻数 dbMaxCount
    计算当前频道下新闻数dbCount,如果dbCount > dbMaxCount,就删除旧的数据

这两种思路,我采用了第二种设定缓存的新闻数目,第一种更简单

NIPNewsDatabase.h


#import 

@interface NIPNewsDatabase : NSObject
/**
 *  保存新闻数据到数据库
 *
 *  @param json       json
 *  @param categoryId 新闻的频道
 */
+ (void)saveData:(NSDictionary *)json categoryId:(NSInteger)categoryId;

/**
 *  根据频道返回新闻数据
 *
 *  @param categoryId 新闻频道
 */
+ (NSArray *)getJsonWithCategoryId:(NSInteger)categoryId;

/**
 *  删除数据库
 */
+ (void)removeDatabase;
@end

NIPNewsDatabase.m

#import "NIPNewsDatabase.h"
#import "FMDB.h"

@implementation NIPNewsDatabase

static FMDatabase *_db;

#define path [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"newsApiResponse.sqlite"]

+ (void)initialize
{
    // 1.打开数据库
    _db = [FMDatabase databaseWithPath:path];
    [_db open];
    
    // 2.创表
    [_db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_newsApiResponse (id integer PRIMARY KEY, newsApiResponse blob NOT NULL, categoryId integer NOT NULL ,time integer NOT NULL);"];
}

+ (NSArray *)getJsonWithCategoryId:(NSInteger)categoryId
{
    NSString * categoryIdStr = [NSString stringWithFormat:@"%ld",(long)categoryId];
    FMResultSet * set = [_db executeQuery:@"SELECT * FROM t_newsApiResponse WHERE categoryId=?;",categoryIdStr];
    NSMutableArray * resultArr = [NSMutableArray array];
    while (set.next) {
        NSData * newsData = [set objectForColumnName:@"newsApiResponse"];
        NSDictionary * result = [NSKeyedUnarchiver unarchiveObjectWithData:newsData];
        [resultArr addObject:result];
    }
    return resultArr;
}

+ (void)saveData:(NSDictionary *)json categoryId:(NSInteger)categoryId
{
    // 1.保存最新的数据
    NSData * newsData = [NSKeyedArchiver archivedDataWithRootObject:json];
    [_db executeUpdateWithFormat:@"INSERT INTO t_newsApiResponse(newsApiResponse, categoryId, time) VALUES (%@, %ld, %@);", newsData, (long)categoryId, @((NSInteger)[[NSDate date] timeIntervalSince1970])];

    // 2.设置最大缓存数;
    int dbMaxCount = 10;
    
    // 3.获得数据库中的条数
    int dbCount = 0;
    NSMutableArray * dbIDs = [NSMutableArray array];
    FMResultSet * set = [_db executeQuery:@"SELECT * FROM t_newsApiResponse WHERE categoryId = ?;",[NSString stringWithFormat:@"%ld",(long)categoryId]];
    while (set.next) {
        dbCount ++;
        int ID = [set intForColumnIndex:0];
        [dbIDs addObject:@(ID)];
    }
    
    // 4.删除多余的数据
    if (dbCount > dbMaxCount) {
        int beyondID = [dbIDs[dbCount-dbMaxCount] intValue];
        NSString * deleteSql = [NSString stringWithFormat:@"DELETE FROM t_newsApiResponse WHERE categoryId = '%ld' AND id < '%d'",categoryId,beyondID];
        if (![_db executeUpdate:deleteSql]) {
            NIPLog(@"数据库删除失败");
        }
    }
}

+ (void)removeDatabase
{
    NSFileManager * fileManager = [[NSFileManager alloc] init];
    [fileManager removeItemAtPath:path error:nil];
}

在VC中

// 从数据中加载数据
- (void)loadDataFromeDB
{
    // 进入界面先从数据库中取数据
    NSArray * responses = [NIPNewsDatabase getJsonWithCategoryId:[self.categoryId integerValue]];
    
    if (responses.count) {
        for (NSDictionary * dict in responses) {
            NSArray * array = [NIPNews mj_objectArrayWithKeyValuesArray:dict[@"News"]];
            [self.newsArray addObjectsFromArray:array];
            [self.tableView reloadData];
        }
    }else{ // 数据库中不存在数据,执行网络刷新
        [self.tableView.mj_header beginRefreshing];
    }
}
// 网络请求
- (void)loadNewsData
{
    [NIPHttpManager.tasks makeObjectsPerformSelector:@selector(cancel)];
    
    NSString * urlStr ;
    NSMutableDictionary * param = [NSMutableDictionary dictionary];
    
    if (self.categoryId.intValue == 0 && self.newsArray.count == 0) {
        urlStr = @"News?count=15";
        param = nil;
    }
    
    if (self.categoryId.intValue == 0 && self.newsArray.count) {
        urlStr = @"News?fromUser=true";
        param = nil;
    }
    
    if (self.categoryId.intValue && self.newsArray.count == 0) {
        urlStr = @"News";
        param[@"categoryId"] = self.categoryId;
        param[@"count"] = @(15);
    }
    
    if (self.categoryId.intValue && self.newsArray.count) {
        urlStr = @"News";
        param[@"categoryId"] = self.categoryId;
        param[@"count"] = @(8);
    }
    
    [NIPHttpManager GET:NIPURL(urlStr) parameters:param progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 保存到数据库
        [NIPNewsDatabase saveData:responseObject categoryId:[self.categoryId integerValue]];
        
        NSArray * array = [NIPNews mj_objectArrayWithKeyValuesArray:responseObject[@"News"]];
        NSRange range = NSMakeRange(0, array.count);
        NSIndexSet * set = [NSIndexSet indexSetWithIndexesInRange:range];
        [self.newsArray insertObjects:array atIndexes:set];
        [self.tableView reloadData];
        
        [self showNewStatusCount:array.count];
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self showNewStatusCount:0];
        [self.tableView.mj_header endRefreshing];
    }];
}

调试用了SimPholder 和 Navicat for SQLite两个软件

realm数据缓存新贵,性能高,操作简单。在json转模型的时候配合使用jsonmodel工具可以将复杂的json(嵌套多层)直接转成realm格式的model类,之前想尝试用realm做缓存的,因为模型都已经建好,不想再按照realm的格式改,所以就继续用了FMDB。

你可能感兴趣的:(项目中数据缓存以及FMDB的使用)