新浪微博客户端(60)-离线缓存微博数据
Posted 夜行过客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了新浪微博客户端(60)-离线缓存微博数据相关的知识,希望对你有一定的参考价值。
很多应用在第一次加载时会读取前一次浏览的历史微博数据,只有当用户手动触发下拉刷新之后,才会去加载新的微博数据。
1.集成FMDB
FMDB是在sqlite3的C语言查询函数基础上封装的一套OC的API,因此在使用之前需要首先导入libsqlite3.tbd.
2. 添加FMDB库
3. 参考代码:
DJStatusDBHelper.h
#import <Foundation/Foundation.h> @class DJStatus; @interface DJStatusDBHelper : NSObject /** 保存单条微博 */ + (void)saveStatus:(NSDictionary *)statusDictionary; /** 保存多条微博 */ + (void)saveMutableStatus:(NSArray *)statusArray; /** 返回指定个数的微博,默认为20 */ + (NSArray *)statusesWithFixNums; /** 返回比maxId小于或等于的微博 */ + (NSArray *)statusesWithMaxId:(NSString *)max_id; /** 返回比since_Id大的微博 */ + (NSArray *)statusesWithSinceId:(NSString *)since_id; @end
DJStatusDBHelper.m
#import "DJStatusDBHelper.h" #import "FMDatabase.h" #import "DJStatus.h" static FMDatabase *_db; @implementation DJStatusDBHelper // 在这个类第一次被实例化的时候创建数据库并打开对应的数据表 + (void)initialize { NSString *db_path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"status.sqlite"]; _db = [FMDatabase databaseWithPath:db_path]; // 1. 打开数据库 [_db open]; // 2. 创表 NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS t_status(id integer PRIMARY KEY, status blob NOT NULL, idstr text NOT NULL);"]; [_db executeUpdate:sql]; } /** 保存单条微博 */ + (void)saveStatus:(NSDictionary *)statusDictionary { // 这里需要注意,如果要将对象保存到SQLite数据库,那么这个对象必须转换为NSData对象,且该对象必须实现NSCoding协议 NSData *statusData = [NSKeyedArchiver archivedDataWithRootObject:statusDictionary]; [_db executeUpdateWithFormat:@"INSERT INTO t_status(status,idstr) VALUES(%@,%@);",statusData,statusDictionary[@"idstr"]]; } /** 保存多条微博 */ + (void)saveMutableStatus:(NSArray *)statusArray { for (int i = 0; i < statusArray.count; i++) { NSDictionary *statusDict = statusArray[i]; [self saveStatus:statusDict]; } } /** 返回指定个数的微博 */ + (NSArray *)statusesWithFixNums { FMResultSet *set = [_db executeQueryWithFormat:@"SELECT * FROM t_status ORDER BY idstr DESC LIMIT 20;"]; NSMutableArray *statusDictArray = [NSMutableArray array]; while (set.next) { NSData *statusData = [set objectForColumnName:@"status"]; NSDictionary *statusDict = [NSKeyedUnarchiver unarchiveObjectWithData:statusData]; [statusDictArray addObject:statusDict]; } return statusDictArray; } /** 返回比since_Id大的微博 */ + (NSArray *)statusesWithSinceId:(NSString *)since_id { FMResultSet *set = [_db executeQueryWithFormat:@"SELECT * FROM t_status WHERE idstr > %@ ORDER BY idstr DESC LIMIT 20;",since_id]; NSMutableArray *statusDictArray = [NSMutableArray array]; while (set.next) { NSData *statusData = [set objectForColumnName:@"status"]; NSDictionary *statusDict = [NSKeyedUnarchiver unarchiveObjectWithData:statusData]; [statusDictArray addObject:statusDict]; } return statusDictArray; } /** 返回比maxId小于或等于的微博 */ + (NSArray *)statusesWithMaxId:(NSString *)max_id { FMResultSet *set = [_db executeQueryWithFormat:@"SELECT * FROM t_status WHERE idstr <= %@ ORDER BY idstr DESC LIMIT 20;",max_id]; NSMutableArray *statusDictArray = [NSMutableArray array]; while (set.next) { NSData *statusData = [set objectForColumnName:@"status"]; NSDictionary *statusDict = [NSKeyedUnarchiver unarchiveObjectWithData:statusData]; [statusDictArray addObject:statusDict]; } return statusDictArray; } @end
DJHomeViewController.m
- (void)pullToRefresh:(MJRefreshHeader *)header { // 判断是否是第一次刷新。根据statusFrame是否有值,如果有,则代表已经加载过数据;若没有,则代表首次加载 if (self.statusFrames.count) { [self loadRefreshStatusesFromNetwork:header]; } else { // 尝试从数据库中加载数据 [self loadRefreshStatusesFromDatabase:header]; } } /** 尝试从数据库中加载数据 */ - (void)loadRefreshStatusesFromDatabase:(MJRefreshHeader *)header { DJLog(@"下拉刷新--从数据库"); NSArray *statuses = [DJStatusDBHelper statusesWithFixNums]; if (statuses.count) { // 1. 将刷新获取到的新数据添加到总数组的头部 NSArray *newStatuses = [DJStatus mj_objectArrayWithKeyValuesArray:statuses]; NSArray *newStatusFrames = [self statusFramesWithStatus:newStatuses]; NSRange range = NSMakeRange(0, newStatusFrames.count); NSIndexSet *indexSet = [[NSIndexSet alloc] initWithIndexesInRange:range]; [self.statusFrames insertObjects:newStatusFrames atIndexes:indexSet]; // 2. 刷新TableView [self.tableView reloadData]; // 3. 结束刷新 [header endRefreshing]; // 4. 清除未读微博数量 [self clearAllBadgeTips]; // 5. 提示当前刷新微博数量 [self showRefreshStatusesNums:newStatusFrames.count]; } else { DJLog(@"下拉刷新--数据库没有,切换到网络"); // 尝试从网络上加载数据 [self loadRefreshStatusesFromNetwork:header]; } } /** 尝试从网络上加载数据*/ - (void)loadRefreshStatusesFromNetwork:(MJRefreshHeader *)header { DJLog(@"下拉刷新--从网络"); AFHTTPSessionManager *requestManager = [AFHTTPSessionManager manager]; NSString *urlString = @"https://api.weibo.com/2/statuses/friends_timeline.json"; NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"access_token"] = [DJAccountTool account].access_token; DJStatusCellFrame *statusFrame = [self.statusFrames firstObject]; if (statusFrame) { params[@"since_id"] = statusFrame.status.idstr; } [requestManager GET:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary * _Nullable responseObject) { // DJLog(@"%@",responseObject); // 0. 将刷新获取到的数据先添加到数据库 [DJStatusDBHelper saveMutableStatus:responseObject[@"statuses"]]; // 1. 将刷新获取到的新数据添加到总数组的头部 NSArray *newStatuses = [DJStatus mj_objectArrayWithKeyValuesArray:responseObject[@"statuses"]]; NSArray *newStatusFrames = [self statusFramesWithStatus:newStatuses]; NSRange range = NSMakeRange(0, newStatusFrames.count); NSIndexSet *indexSet = [[NSIndexSet alloc] initWithIndexesInRange:range]; [self.statusFrames insertObjects:newStatusFrames atIndexes:indexSet]; // 2. 刷新TableView [self.tableView reloadData]; // 3. 结束刷新 [header endRefreshing]; // 4. 清除未读微博数量 [self clearAllBadgeTips]; // 5. 提示当前刷新微博数量 [self showRefreshStatusesNums:newStatusFrames.count]; } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { [header endRefreshing]; }]; } /** 下载加载更多 */ - (void)loadMoreStatuses:(MJRefreshFooter *)footer { DJStatusCellFrame *statusFrame = [self.statusFrames lastObject]; if (statusFrame) { long long max_id = [statusFrame.status.idstr longLongValue] - 1; [self loadMoreStatusesFromDatabaseWithMaxId:[NSString stringWithFormat:@"%lld",max_id] footer:footer]; } else { [self loadMoreStatusesFromNetworkWithMaxId:[NSString stringWithFormat:@"%d",0] footer:footer]; } } /** 载入更多数据从数据库 */ - (void)loadMoreStatusesFromDatabaseWithMaxId:(NSString *)max_id footer:(MJRefreshFooter *)footer{ DJLog(@"加载更多--从数据库"); NSArray *statuses = [DJStatusDBHelper statusesWithMaxId:max_id]; if (statuses.count) { // 1. 将刷新获取到的新数据添加到总数组的尾部 NSArray *newStatuses = [DJStatus mj_objectArrayWithKeyValuesArray:statuses]; NSArray *newStatusFrames = [self statusFramesWithStatus:newStatuses]; [self.statusFrames addObjectsFromArray:newStatusFrames]; // 2. 刷新TableView [self.tableView reloadData]; // 3. 结束刷新 [footer endRefreshing]; } else { DJLog(@"加载更多--数据库没有,切换到网络"); // 尝试从网络获取 [self loadMoreStatusesFromNetworkWithMaxId:max_id footer:footer]; } } /** 载入更多数据从网络 */ - (void)loadMoreStatusesFromNetworkWithMaxId:(NSString *)max_id footer:(MJRefreshFooter *)footer{ DJLog(@"加载更多--从网络"); AFHTTPSessionManager *requestManager = [AFHTTPSessionManager manager]; NSString *urlString = @"https://api.weibo.com/2/statuses/friends_timeline.json"; NSMutableDictionary *params = [NSMutableDictionary dictionary]; params[@"access_token"] = [DJAccountTool account].access_token; DJStatusCellFrame *statusFrame = [self.statusFrames lastObject]; if (statusFrame) { long long max_id = [statusFrame.status.idstr longLongValue] - 1; params[@"max_id"] = @(max_id); } [requestManager GET:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary * _Nullable responseObject) { // 0.将刷新获取到的数据添加到数据库 [DJStatusDBHelper saveMutableStatus:responseObject[@"statuses"]]; // 1. 将刷新获取到的新数据添加到总数组的尾部 NSArray *newStatuses = [DJStatus mj_objectArrayWithKeyValuesArray:responseObject[@"statuses"]]; NSArray *newStatusFrames = [self statusFramesWithStatus:newStatuses]; [self.statusFrames addObjectsFromArray:newStatusFrames]; // 2. 刷新TableView [self.tableView reloadData]; // 3. 结束刷新 [footer endRefreshing]; } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { [footer endRefreshing]; }]; }
最终效果:
以上是关于新浪微博客户端(60)-离线缓存微博数据的主要内容,如果未能解决你的问题,请参考以下文章