(一一六)新浪微博client的離線緩存實現思路
上一節(一一五)利用NSKeyedArchiver實現隨意對象轉為二進制介紹了將隨意對象轉化為二進制數據和還原的方法。可用於實現本節介紹的微博數據離線緩存。
通過新浪官方的API能夠發現,返回的微博數據例如以下樣式:
{ "statuses": [ { "created_at": "Tue May 31 17:46:55 +0800 2011", "id": 11488058246, "text": "求關註。", "source": "<a href="http://weibo.com" rel="nofollow">新浪微博</a>", "favorited": false, "truncated": false, "in_reply_to_status_id": "", "in_reply_to_user_id": "", "in_reply_to_screen_name": "", "geo": null, "mid": "5612814510546515491", "reposts_count": 8, "comments_count": 9, "annotations": [], "user": { "id": 1404376560, "screen_name": "zaku", "name": "zaku", "province": "11", "city": "5", "location": "北京 朝陽區", "description": "人生五十年,乃如夢如幻;有生斯有死,壯士復何憾。
", "url": "http://blog.sina.com.cn/zaku", "profile_image_url": "http://tp1.sinaimg.cn/1404376560/50/0/1", "domain": "zaku", "gender": "m", "followers_count": 1204, "friends_count": 447, "statuses_count": 2908, "favourites_count": 0, "created_at": "Fri Aug 28 00:00:00 +0800 2009", "following": false, "allow_all_act_msg": false, "remark": "", "geo_enabled": true, "verified": false, "allow_all_comment": true, "avatar_large": "http://tp1.sinaimg.cn/1404376560/180/0/1", "verified_reason": "", "follow_me": false, "online_status": 0, "bi_followers_count": 215 } }, ... ], "ad": [ { "id": 3366614911586452, "mark": "AB21321XDFJJK" }, ... ], "previous_cursor": 0, // 暫未支持 "next_cursor": 11488013766, // 暫未支持 "total_number": 81655 }
獲取數據的關鍵,在於statuses的抓取上,通常情況下我們向新浪的server發送請求,接收到響應體,取出statuses字典數組後進行處理。如今我們要實現的是進入client時先推斷有沒有緩存過數據。緩存過則直接顯示已經緩存的數據。而不直接通過網絡請求。
離線緩存通過iOS自帶的SQLite3實現。
關於數據庫的使用請參考文章使用FMDB操作SQLite數據庫,本文重點是緩存思路。
微博有一個唯一標誌idstr用於標識微博的先後順序,idstr越大的微博越新,我們的緩存思路是把微博字典數組中的每一條微博都用NSKeyedArchiver轉化為二進制存入數據庫的status字段,然後再把idstr存儲到idstr字段,通過對idstr排序、和當前要求的id範圍比較就能夠正確推斷出數據的新舊關系。
在給新浪發送數據時,假設是載入新數據。會在參數中增加一個since_id,表示僅僅載入這個id之後的微博。假設是載入舊數據,會在參數中增加一個max_id,表示僅僅載入這個之前的。
因此在緩存數據時,僅僅接收微博字典數組就可以。在讀取緩存時,傳入請求參數,推斷參數中有無since_id、max_id就可以。緩存方法均為類方法,為了能拿到數據庫,使用一個靜態成員變量管理。而且在類的公共初始化方法中打開數據庫,假設沒有創建過表則創建。
數據庫的打開:
static FMDatabase *_db; + (void)initialize{ // 公共類初始化方法 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"statuses.sqlite"]; _db = [FMDatabase databaseWithPath:path]; [_db open]; [_db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_status (id integer PRIMARY KEY, status blob NOT NULL, idstr text NOT NULL)"]; }
緩存的方法:
+ (NSArray *)statusesWithParams:(NSDictionary *)params{ 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"]]; }else{ // 無條件載入最前面20條 sql = [NSString stringWithFormat:@"SELECT * FROM t_status ORDER BY idstr DESC LIMIT 20"]; } // 運行查詢 FMResultSet *set = [_db executeQuery:sql]; NSMutableArray *statuses = [NSMutableArray array]; while (set.next) { NSData *dictData = [set objectForColumnName:@"status"]; NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:dictData]; [statuses addObject:dict]; } return statuses; } + (void)saveStatuses:(NSArray *)statuses{ for (NSDictionary *statusDict in statuses) { NSData *dictData = [NSKeyedArchiver archivedDataWithRootObject:statusDict]; [_db executeUpdateWithFormat:@"INSERT INTO t_status (status, idstr)VALUES(%@,%@)",dictData,statusDict[@"idstr"]]; } }
在運行網絡請求時。調用讀取緩存的方法。假設得到的數組中有元素,則不進行網絡請求。而是對緩存的字典轉模型。然後進一步操作,這樣就完畢了緩存。
(一一六)新浪微博client的離線緩存實現思路