EasyDataKit 是一個基於 FMDB 封裝的庫,它可以免去開發者編寫複雜 SQL 的困擾,更加專注業務上的事情,從而提高開發效率。
特徵
- 類 ORM 介面
- 自動建立庫和表,支援表新增欄位的修改
- 支援 where 查詢語句
- 自動事務提升插入效率
使用
EasyDataKit 適用於將網路請求的資料持久化到資料庫中,特別是處理網路請求資料時不習慣把資料轉換成 model。筆者的淺見是:轉換對效能是有消耗的,獲得的可讀性好處也可以通過字串常量解決。(這兒有篇探討)
假設你通過網路請求獲取到了資料:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
{ "data": { "id": "56d177a27cb3331100465f72", "messagePrefix": "飯否每日精選", "content": "飯否每日精選", "topicId": 1345, "briefIntro": "飯否是國內著名的小眾輕部落格社群,氛圍獨特,清新自由。關注飯否每日精選,看看塵囂之外,大家談論什麼。", "keywords": "飯否 精選 短部落格 社群", "timeForRank": "2016-02-27T11:06:30.731Z", "lastMessagePostTime": "2016-11-06T02:42:52.111Z", "topicPublishDate": "2016-02-26T16:00:00.000Z", "createdAt": "2016-02-27T10:17:06.295Z", "updatedAt": "2016-11-01T04:30:08.973Z", "subscribersCount": 1207100, "subscribedStatusRawValue": 1, "subscribedAt": "2016-10-18T09:57:24.424Z", "rectanglePicture": { "thumbnailUrl": "https://cdn.ruguoapp.com/o_1ach3c6o011j91ljjtmdhlhnffo.jpg?imageView2/1/w/120/h/180", "middlePicUrl": "https://cdn.ruguoapp.com/o_1ach3c6o011j91ljjtmdhlhnffo.jpg?imageView2/1/w/200/h/300", "picUrl": "https://cdn.ruguoapp.com/o_1ach3c6o011j91ljjtmdhlhnffo.jpg?imageView2/0/h/1000", "format": "png" }, "squarePicture": { "thumbnailUrl": "https://cdn.ruguoapp.com/o_1ach6nm599m94re1gvj14r71jaso.jpg?imageView2/0/w/120/h/120", "middlePicUrl": "https://cdn.ruguoapp.com/o_1ach6nm599m94re1gvj14r71jaso.jpg?imageView2/0/w/300/h/300", "picUrl": "https://cdn.ruguoapp.com/o_1ach6nm599m94re1gvj14r71jaso.jpg?imageView2/0/h/1000", "format": "png" }, "pictureUrl": "https://cdn.ruguoapp.com/o_1ach3c6o011j91ljjtmdhlhnffo.jpg?imageView2/1/w/200/h/300", "thumbnailUrl": "https://cdn.ruguoapp.com/o_1ach6nm599m94re1gvj14r71jaso.jpg?imageView2/0/w/300/h/300" } } |
你可將這段 JSON String 轉換成 Dictionary 或 Array:
1 2 |
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil]; NSDictionary *subscribe = dictionary[@"data"]; |
接著便可使用 EasyDataKit 的 API 進行儲存:
1 2 |
EDKEntity *subscribeEntity = [[EDKEntity alloc] initWithTableName:@"subcribes" dbName:nil]; [subscribeEntity saveData:subscribe primaryColumn:@"id" relationShip:nil indexes:nil]; |
可以手動為資料新增列,實現滿足業務的需求:
1 2 3 |
NSMutableDictionary *subcribeInfo = [[NSMutableDictionary alloc] initWithDictionary:subscribe]; [subcribeInfo setObject:<a href="http://www.jobbole.com/members/yaowei729">@1</a> forKey:@"isSubcribed"]; EDKEntity *subscribeEntity = [[EDKEntity alloc] initWithTableName:@"subcribes" dbName:nil]; [subscribeEntity saveData:subcribeInfo primaryColumn:@"id" relationShip:nil indexes:nil]; |
如果你想讓某紀錄關聯其它物件,可以將物件儲存後返回的 id 作為 value,key 是該紀錄原本對應該物件的欄位,這相當於用 id 這個值去替換原本欄位對應的物件,從而達到拆分的目的:
1 2 3 |
id rowId = [rectanglePictureEntity saveData:subscribe[@"rectanglePicture"] primaryColumn:nil relationShip:nil]; EDKEntity *subscribeEntity = [[EDKEntity alloc] initWithTableName:@"subcribes" dbName:nil]; [subscribeEntity saveData:subscribe primaryColumn:@"id" relationShip:@{@"rectanglePicture": rowId} indexes:nil]; |
EasyDataKit 還可以儲存索引
1 2 3 |
NSDictionary *subcribeInfo = [[NSDictionary alloc] initWithDictionary:subscribe]; EDKEntity *subscribeEntity = [[EDKEntity alloc] initWithTableName:@"subcribes" dbName:@"TestIndex"]; [subscribeEntity saveData:subcribeInfo primaryColumn:nil relationShip:nil indexes:@[@[@"topicId"], @[@"content", @"messagePrefix"]]]; |
對儲存來說,EasyDataKit 還提供了自動 ALTER TABLE 新增列的功能,方便開發者應對升級,原理是當檢測到待儲存的字典 keys 陣列元素個數比之前已經在表中的列多時,則會自動為表新增新的列,即並不支援修改列和刪除列的操作,而 EasyDataKit 對建立的索引是支援修改刪除的。
查詢:
1 2 3 4 5 6 |
// select by id EDKEntity *entity = [[EDKEntity alloc] initWithTableName:@"messages" dbName:nil]; id object = [entity queryByPrimaryKey:@"581d2fdb36a4471100e311d6" withColumns:@[@"topicId", @"commentCount", @"topic"]]; NSLog(@"%@", object); NSArray *objects = [entity queryWithColumns:nil where:@"WHERE commentCount < ? and read = ?" arguments:@[@20, @1]]; NSLog(@"%@", objects); |
查詢巢狀物件並將其轉換為 Dictionary 或 Array:
1 2 3 4 5 6 7 8 9 10 |
EDKEntity *subcribeEntity = [[EDKEntity alloc] initWithTableName:@"subcribes" dbName:nil]; // select by id id subcribe = [subcribeEntity queryByPrimaryKey:@"56d177a27cb3331100465f72" withColumns:@[@"squarePicture"]]; // subcribe is a json string NSData *data = [subcribe[@"squarePicture"] dataUsingEncoding:NSUTF8StringEncoding]; NSError *error; NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; NSLog(@"JSONDict: %@", jsonDict); |
更新:
1 2 3 |
EDKEntity *entity = [[EDKEntity alloc] initWithTableName:@"messages" dbName:nil]; [entity updateByPrimaryKey:@"5805905a319a9c1200833660" set:@{@"read": @"0", @"commentCount": @99}]; [entity updateWithSet:@{@"messageId": @"2333333"} where:@"WHERE commentCount > ?" arguments:@[@50]]; |
刪除:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
EDKEntity *entity = [[EDKEntity alloc] initWithTableName:@"messages" dbName:nil]; // delete by id [entity deleteByPrimaryKey:@"5805905a319a9c1200833660"]; // delete by where [entity deleteWithWhere:@"WHERE popularity = ?" arguments:@[@"93"]]; // delete all [entity deleteAll]; |
1 2 3 4 5 6 7 8 9 |
EDKEntity *entity = [[EDKEntity alloc] initWithTableName:@"messages" dbName:nil]; // delete by id [entity deleteByPrimaryKey:@"5805905a319a9c1200833660"]; // delete by where [entity deleteWithWhere:@"WHERE popularity = ?" arguments:@[@"93"]]; // delete all [entity deleteAll]; |
由上面可以看出,只要建立出 EDKEntity 物件,就可以輕鬆加愉快地進行儲存,查詢,修改,刪除操作。開發者無需建立資料庫、表,EasyDataKit 也支援 db 的劃分,但不提供記憶體快取,原因是筆者認為沒有熱塊的資料庫快取意義不是太大。當有寫操作發生的時候,EasyDataKit 會通過輪詢的事務機制打包寫操作,從而提高頻繁寫操作的效率。(更詳細的使用請移步 EasyDataKit 中的 Example)
原始碼簡析
EasyDataKit 有個 swizzle 了 NSMutableDictionary 的 setObject:forKey: 和 NSMutableArray 的 addObject:,使得應對空值不會 crash。
EasyDataKit 還有個遞迴方法:dealWithObject:,主要有兩個用途:一是用來檢測除了 NSDictionary、NSArray、NSString、NSNumber、NSNull 這些型別以外的合法性,譬如 UIView 型別直接呼叫 description 轉換成字串;二是為了能讓巢狀的 Dictionary 或 Array 以 JSON String 的形式存入資料庫,在取出後仍可以將其轉換回 Dictionary 或 Array。
DISPATCH_SOURCE_TYPE_TIMER 建立的定時器。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!