美文网首页
项目中数据缓存以及FMDB的使用

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

作者: 彡廿 | 来源:发表于2016-09-19 18:43 被阅读411次

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

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

    屏幕快照 2016-09-19 下午6.14.22.png

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

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

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

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

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

    NIPNewsDatabase.h

    
    #import <Foundation/Foundation.h>
    
    @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<NIPNews *> * 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<NIPNews *> * 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的使用

          本文链接:https://www.haomeiwen.com/subject/nosnettx.html