iOS开发程序员编程知识点

使用FMDB做离线缓存的例子(iOS)

2016-08-10  本文已影响2694人  訷訷

本文以仿微博的应用为基础,实现使用FMDB做离线缓存

仿微博下拉
仿微博上拉

设计思路:

分析加载微博过程:
  1. 尝试从沙盒加载缓存数据
  2. 有缓存,直接加载缓存
  3. 无缓存,发送请求,展示返回的数据,将数据存入沙盒


    加载微博过程.png
分析微博返回数据:
  1. 需要加载的微博多,数据量大,不适合用plist和NSCoding这类一次性加载和存储全部数据的方法,使用数据库则可以做到取一部分数据和存一部分的数据
  2. 由于微博模型多,如果按照后台服务器一样,一个模型建一张表,每个表(如:用户,微博,图片,文字)又相互之间通过外键联系,会导致客户端的数据库过于复杂,所以只建一张表
  3. 每条微博的字段非常多,在客户端数据库表中也创建相应数量的字段保存数据是不适合的,所以可以在数据库表中只创建一个blob类型的status字段保存每条微博的全部数据
  4. 每条微博是根据自身字段idstr大小来比较新旧的,把每条微博从数据库取出再取出idstr来比较新旧是不适合的,所以表中还应该增加idstr字段方便查询
  5. 最终确定建一张表,三个字段:id(系统默认),status,idstr
微博模型较多
微博的字段非常多
表结构

实现步骤

步骤1.创建一个工具类StatusTool

步骤2.在StatusTool的initialize中初始化数据库

static FMDatabase *_db;
+ (void)initialize
{
    // 1.打开数据库
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"statuses.sqlite"];
    _db = [FMDatabase databaseWithPath:path];
    [_db open];
    
    // 2.创表
    [_db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_status (id integer PRIMARY KEY, status blob NOT NULL, idstr text NOT NULL);"];
}```

步骤3. StatusTool实现存储方法

步骤4. StatusTool实现取缓存方法

+ (NSArray *)statusesWithParams:(NSDictionary *)params
{
    // 根据请求参数生成对应的查询SQL语句
    NSString *sql = nil;
    if (params[@"since_id"]) { // 下拉刷新
        sql = [NSString stringWithFormat:@"SELECT * FROM t_status WHERE idstr > %@ ORDER BY idstr DESC LIMIT 20;", params[@"since_id"]];
    } else if (params[@"max_id"]) { // 上拉刷新
        sql = [NSString stringWithFormat:@"SELECT * FROM t_status WHERE idstr <= %@ ORDER BY idstr DESC LIMIT 20;", params[@"max_id"]];
    }
    
    // 执行SQL
    FMResultSet *set = [_db executeQuery:sql];
    NSMutableArray *statuses = [NSMutableArray array];
    while (set.next) {
        NSData *statusData = [set objectForColumnName:@"status"];
        NSDictionary *status = [NSKeyedUnarchiver unarchiveObjectWithData:statusData];
        [statuses addObject:status];
    }
    return statuses;
}```

步骤5.方法调用:

/**

/**

遇到问题:

如果把NSDictionary字典数据status直接通过[_db executeUpdateWithFormat:@"INSERT INTO t_status(status, idstr) VALUES (%@, %@);", status, status[@"idstr"]];来存储,就会取不出来。
原因是通过%@来传入字典对象,相当于传入[status description];,打印类型可以发现取出的是字符串,不是我们预期的字典对象。
解决方法:
把字典用NSData *statusData = [NSKeyedArchiver archivedDataWithRootObject:status];转成NSData再存入数据库。
取出数据时,用NSDictionary *status = [NSKeyedUnarchiver unarchiveObjectWithData:statusData];再转成字典。

为什么字典对象能转成NSData类型

字典对象能转成NSData类型的本质是遵守了NSCoding协议,所以如果想要把自定义对象转成NSData类型需要遵守NSCoding协议,实现encodeWithCoder和initWithCoder方法

例:自定义对象

@interface Shop : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) double  price;
@end

@implementation Shop
- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeDouble:self.price forKey:@"price"];
}

- (id)initWithCoder:(NSCoder *)decoder
{
    if (self = [super init]) {
        self.name = [decoder decodeObjectForKey:@"name"];
        self.price = [decoder decodeDoubleForKey:@"price"];
    }
    return self;
}
@end```
上一篇 下一篇

猜你喜欢

热点阅读