离线缓存有多种方案,

一.什么是离线缓存?

离线缓存就是把用户访问过的数据存到本地的数据库中,下次打开App时首先展示上次查阅过得数据(如同微信),然后再刷新请求网络获取新的数据。

以新浪微博请求网络流程图为例:
图片描述

思考一个问题,本地缓存需要创建多少张表,保存哪些内容呢?以新浪微博的一条微博为例:
图片描述

第一种思路:

设计三张表,用户表,微博内容表,图片表(包含缩略图、中等图、大图等)

第二种思路:

为了简单,只用一张表,将服务器接口所返回的json数据直接存入表中,用的时候只需从表中解析即可 。

表结构设计:
图片描述

access_token:一个access_token代表一个账号,如果一个用户有多个账号,则每个账号对应不同的缓存数据,即用来处理多账号登陆的问题。

二.离线缓存项目中实现

第一次网络请求后,存在缓存,下次进入后直接从缓存中获取数据。

//  IWStatusTool.m
//  ItcastWeibo
//
//  Created by kaiyi on 16-6-3.
//  Copyright (c) 2016年 itcast. All rights reserved.

#import "IWStatusCacheTool.h"

+(void)homeStatusesWithParam:(IWHomeStatusesParam *)param success:(void (^)(IWHomeStatusesResult *))success failure:(void (^)(NSError *))failure
{
    // 1.先从缓存里边加载
    NSArray *dicArray = [IWStatusCacheTool statuesWithParam:param];
    if(dicArray.count){ // 有缓存
        // 传递了block
        if (success) {
            IWHomeStatusesResult *result = [[IWHomeStatusesResult alloc] init];
            
            result.statuses = [IWStatus objectArrayWithKeyValuesArray:dicArray];
            
            success(result);
        }
    }
    else
    {
        [IWHttpTool getWithURL:@"https://api.weibo.com/2/statuses/home_timeline.json" params:param.keyValues success:^(id json)
         {
             // 缓存 -[2016-07-09 add]
             [IWStatusCacheTool addStatuses:json[@"statuses"]];
             // NSArray *dictArray = json[@"status"];
             
             
             // 请求成功后,新浪返回类型为字典的json,这里需要将字典转为模型
             if(success){
                 IWHomeStatusesResult *result = [IWHomeStatusesResult objectWithKeyValues:json];
                 
                 success(result);
             }
             
         } failure:^(NSError *error) {
             if(failure){
                 failure(error);
             }
         }];

        
    }
}

封装一个离线cache的工具类:
IWStatusCacheTool.m

//
//  IWStatusCacheTool.m
//  ItcastWeibo
//
//  Created by kaiyi on 16-7-9.
//  Copyright (c) 2016年 itcast. All rights reserved.
//

#import "IWStatusCacheTool.h"
#import "IWAccount.h"
#import "IWAccountTool.h"
#import "FMDB.h"

@implementation IWStatusCacheTool

static FMDatabaseQueue *_queue;

+(void)initialize{
    
    // 0.获得沙盒中的数据库文件名
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"statuses.sqlite"];
    
    // 1.创建队列
    _queue =  [FMDatabaseQueue databaseQueueWithPath:path];
    
    // 2.创表
    [_queue inDatabase:^(FMDatabase *db) {
        [db executeUpdate:@"create table if not exists t_status (id integer primary key autoincrement, access_token text, idstr text, dict blob);"];
    }];
}

+(void)addStatus:(NSDictionary *)dict
{
    [_queue inDatabase:^(FMDatabase *db) {
        NSString *accessToken = [IWAccountTool account].access_token;
        NSString *idstr = dict[@"idstr"];
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dict];
        [db executeUpdate:@"insert into t_status (access_token, idstr, dict) values(?,?,?)", accessToken, idstr, data];
    }];
   
    
}

+(void)addStatuses:(NSArray *)dictArray
{
    for(NSDictionary *dict in dictArray){
        [self addStatus:dict];
    }
    
    
}



+(NSArray *)statuesWithParam:(IWHomeStatusesParam *)param
{
    // 1.定义数组
    __block NSMutableArray *dictArray = nil;
    
    // 2.使用数据库
    [_queue inDatabase:^(FMDatabase *db) {
        
        // 创建数组
        dictArray = [NSMutableArray array];
        
        // accessToken
         NSString *accessToken = [IWAccountTool account].access_token;
        
        FMResultSet *rs = nil;
        if (param.since_id) { // 如果有since_id
            rs = [db executeQuery:@"select * from t_status where access_token = ? and idstr > ? order by idstr desc limit 0,?;", accessToken, param.since_id, param.count];
        } else if (param.max_id) { // 如果有max_id
            rs = [db executeQuery:@"select * from t_status where access_token = ? and idstr <= ? order by idstr desc limit 0,?;", accessToken, param.max_id, param.count];
        } else { // 如果没有since_id和max_id
            rs = [db executeQuery:@"select * from t_status where access_token = ? order by idstr desc limit 0,?;", accessToken, param.count];
        }

        
        while(rs.next){
            NSData *data = [rs dataForColumn:@"dict"];
            NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:data];
            [dictArray addObject:dict];
        }
    }];
    
    return dictArray;
}

@end

项目源代码,请访问github获取微博项目源代码github


Corwien
6.3k 声望1.6k 粉丝

为者常成,行者常至。