EasyDataKit 简单易用的 SQLite 轮子

热血pk007 5年前
   <p>EasyDataKit 是一个基于 FMDB 封装的库,它可以免去开发者编写复杂 SQL 的困扰,更加专注业务上的事情,从而提高开发效率。</p>    <h2><strong>特征</strong></h2>    <ul>     <li>类 ORM 接口</li>     <li>自动创建库和表,支持表新增字段的修改</li>     <li>支持 where 查询语句</li>     <li>自动事务提升插入效率</li>    </ul>    <h2><strong>使用</strong></h2>    <p>EasyDataKit 适用于将网络请求的数据持久化到数据库中,特别是处理网络请求数据时不习惯把数据转换成 model。笔者的浅见是:转换对性能是有消耗的,获得的可读性好处也可以通过字符串常量解决。</p>    <p>假设你通过网络请求获取到了数据:</p>    <pre>  <code class="language-objectivec">{      "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"      }  }  </code></pre>    <p>你可将这段 JSON String 转换成 Dictionary 或 Array:</p>    <pre>  <code class="language-objectivec">NSDictionary *dictionary = [NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingAllowFragmentserror:nil];   NSDictionary *subscribe = dictionary[@"data"];  </code></pre>    <p>接着便可使用 EasyDataKit 的 API 进行存储:</p>    <pre>  <code class="language-objectivec">EDKEntity *subscribeEntity = [[EDKEntity alloc]initWithTableName:@"subcribes"dbName:nil];  [subscribeEntitysaveData:subscribeprimaryColumn:@"id"relationShip:nilindexes:nil];  </code></pre>    <p>可以手动为数据添加列,实现满足业务的需求:</p>    <pre>  <code class="language-objectivec">NSMutableDictionary *subcribeInfo = [[NSMutableDictionary alloc]initWithDictionary:subscribe];  [subcribeInfosetObject:<a href="http://www.jobbole.com/members/yaowei729">@1</a>forKey:@"isSubcribed"];  EDKEntity *subscribeEntity = [[EDKEntity alloc]initWithTableName:@"subcribes"dbName:nil]; [subscribeEntitysaveData:subcribeInfoprimaryColumn:@"id"relationShip:nilindexes:nil];  </code></pre>    <p>如果你想让某纪录关联其它对象,可以将对象存储后返回的 id 作为 value,key 是该纪录原本对应该对象的字段,这相当于用 id 这个值去替换原本字段对应的对象,从而达到拆分的目的:</p>    <pre>  <code class="language-objectivec">id rowId = [rectanglePictureEntitysaveData:subscribe[@"rectanglePicture"]primaryColumn:nilrelationShip:nil];  EDKEntity *subscribeEntity = [[EDKEntity alloc]initWithTableName:@"subcribes"dbName:nil];  [subscribeEntitysaveData:subscribeprimaryColumn:@"id"relationShip:@{@"rectanglePicture": rowId}indexes:nil];  </code></pre>    <p>EasyDataKit 还可以存储索引</p>    <pre>  <code class="language-objectivec">NSDictionary *subcribeInfo = [[NSDictionary alloc]initWithDictionary:subscribe];  EDKEntity *subscribeEntity = [[EDKEntity alloc]initWithTableName:@"subcribes"dbName:@"TestIndex"];  [subscribeEntitysaveData:subcribeInfoprimaryColumn:nilrelationShip:nilindexes:@[@[@"topicId"], @[@"content", @"messagePrefix"]]];  </code></pre>    <p>对存储来说,EasyDataKit 还提供了自动 ALTER TABLE 添加列的功能,方便开发者应对升级,原理是当检测到待存储的字典 keys 数组元素个数比之前已经在表中的列多时,则会自动为表添加新的列,即并不支持修改列和删除列的操作,而 EasyDataKit 对创建的索引是支持修改删除的。</p>    <p>查询:</p>    <pre>  <code class="language-objectivec">// select by id  EDKEntity *entity = [[EDKEntity alloc]initWithTableName:@"messages"dbName:nil];  id object = [entityqueryByPrimaryKey:@"581d2fdb36a4471100e311d6"withColumns:@[@"topicId", @"commentCount", @"topic"]];  NSLog(@"%@", object);  NSArray *objects = [entityqueryWithColumns:nilwhere:@"WHERE commentCount < ? and read = ?"arguments:@[@20, @1]];   NSLog(@"%@", objects);  </code></pre>    <p>查询嵌套对象并将其转换为 Dictionary 或 Array:</p>    <pre>  <code class="language-objectivec">EDKEntity *subcribeEntity = [[EDKEntity alloc]initWithTableName:@"subcribes"dbName:nil];     // select by id id  subcribe = [subcribeEntityqueryByPrimaryKey:@"56d177a27cb3331100465f72"withColumns:@[@"squarePicture"]];     // subcribe is a json string  NSData *data = [subcribe[@"squarePicture"]dataUsingEncoding:NSUTF8StringEncoding];  NSError *error;  NSDictionary *jsonDict = [NSJSONSerializationJSONObjectWithData:dataoptions:0error:&error];   NSLog(@"JSONDict: %@", jsonDict);  </code></pre>    <p>更新:</p>    <pre>  <code class="language-objectivec">EDKEntity *entity = [[EDKEntity alloc]initWithTableName:@"messages"dbName:nil];   [entityupdateByPrimaryKey:@"5805905a319a9c1200833660"set:@{@"read": @"0", @"commentCount": @99}];  [entityupdateWithSet:@{@"messageId": @"2333333"}where:@"WHERE commentCount > ?"arguments:@[@50]];  </code></pre>    <p>删除:</p>    <pre>  <code class="language-objectivec">EDKEntity *entity = [[EDKEntity alloc]initWithTableName:@"messages"dbName:nil];     // delete by id     [entitydeleteByPrimaryKey:@"5805905a319a9c1200833660"];     // delete by where     [entitydeleteWithWhere:@"WHERE popularity = ?"arguments:@[@"93"]];     // delete all     [entitydeleteAll];  </code></pre>    <pre>  <code class="language-objectivec">EDKEntity *entity = [[EDKEntity alloc]initWithTableName:@"messages"dbName:nil];  // delete by id  [entitydeleteByPrimaryKey:@"5805905a319a9c1200833660"];     // delete by where  [entitydeleteWithWhere:@"WHERE popularity = ?"arguments:@[@"93"]];     // delete all  [entitydeleteAll];  </code></pre>    <p>由上面可以看出,只要创建出 EDKEntity 对象,就可以轻松加愉快地进行存储,查找,修改,删除操作。开发者无需创建数据库、表,EasyDataKit 也支持 db 的划分,但不提供内存缓存,原因是笔者认为没有热块的数据库缓存意义不是太大。当有写操作发生的时候,EasyDataKit 会通过轮询的事务机制打包写操作,从而提高频繁写操作的效率。(更详细的使用请移步 EasyDataKit 中的 Example)</p>    <h2><strong>源码简析</strong></h2>    <p>EasyDataKit 有个 swizzle 了 NSMutableDictionary 的 setObject:forKey: 和 NSMutableArray 的 addObject:,使得应对空值不会 crash。</p>    <p>EasyDataKit 还有个递归方法:dealWithObject:,主要有两个用途:一是用来检测除了 NSDictionary、NSArray、NSString、NSNumber、NSNull 这些类型以外的合法性,譬如 UIView 类型直接调用 description 转换成字符串;二是为了能让嵌套的 Dictionary 或 Array 以 JSON String 的形式存入数据库,在取出后仍可以将其转换回 Dictionary 或 Array。</p>    <p>DISPATCH_SOURCE_TYPE_TIMER 创建的定时器。</p>    <p> </p>    <p> </p>    <p>来自:http://ios.jobbole.com/90509/</p>    <p> </p>