新浪微博客戶端(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];
    }];
    
}

最終效果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM