zoukankan      html  css  js  c++  java
  • 新浪微博客户端(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];
        }];
        
    }

    最终效果:

  • 相关阅读:
    Python爬虫IP代理教程,让你不再为IP被封禁发愁
    一个值只有0和1的字段,到底要不要建索引.一个表只有一个字段,用不用索引
    SciVal
    除了article 和 review,还有哪些论文类型
    windows7/10文件夹中搜索指定大小的文件
    国内外大学IP地址段
    教你如何用proxyhunter找大学代理
    SCI JCR ESI等名词解释
    solr全文检索实现原理
    设计一个回调要注意哪些事情
  • 原文地址:https://www.cnblogs.com/yongdaimi/p/6196099.html
Copyright © 2011-2022 走看看