iOS - 最易用的数据库工具类 `XWDatabase` 开源

iOS - 最易用的数据库工具类 XWDatabase 开源

XWDatabase GitHub 地址:https://github.com/qxuewei/XWDatabase

XWDatabase 的亮点

  • 将数据库操作简化到难以想象的程度,你甚至不需要知道数据库的存在,当然更不需要写 SQL 语句,你只需要直接操作模型即可对模型进行增删改查的操作,她会根据模型动态在数据库中创建以当前模型类名为名称的数据库表,当然你也可以自定义表名;
  • 她会根据模型的成员变量和成员变量的类型动态进行字段的设计,有多少成员变量,表中自然就会有多少字段与其对应,当然,你也可以忽略其中的某些你不想存储的成员变量,也可以自定义字段的名称;
  • 如果哪天模型的字段变化了,她会自动进行表中原有字段的更新,而且无论原表中有多少数据,都会一条不落的迁移到新表中;
  • 她的API简单到只有一行代码,你无需关注数据库的开启和关闭,一行代码实现增删改查和数据迁移;
  • 你甚至可以在任何线程中调用她的API,她一定是线程安全的,不会出现多线程访问同一个数据库和死锁的问题;
  • 数据操作是耗时操作,所以你无需手动开启异步线程操作数据库操作,她会统一在一个保活的异步线程中执行;
  • 她支持存储常见的数据类型(int、long、signed、float、double、NSInteger、CGFloat、BOOL、NSString、NSMutableString、NSNumber、NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、NSData、NSMutableData、UIImage、NSDate、NSURL、NSRange、CGRect、CGSize、CGPoint、自定义对象等的存储);
  • 她还对二进制文件的存储做了优化,比如同一张图片表中所有数据都持有这张图片对象,她在数据库中只会有一份拷贝,竭尽她所能优化存储空间。

笔锋一转,V1.0 版本会存在很多不足,希望各位前辈和大牛多多指正,多提 issues

下面简述一下此库的一些设计思路和使用方法

使用

一、增

1.保存一个模型
- (void)saveOnePerson
{
    XWPerson *person = [XWPerson testPerson:2];
    [XWDatabase saveModel:person completion:^(BOOL isSuccess) {

    }];
}

实例化一个对象, 调用 saveModel 方法。

2.保存多个模型
- (void)saveModels
{
    NSMutableArray *persons = [[NSMutableArray alloc] init];
    for (int i = 0; i < 1000; i++) {
        [persons addObject:[XWPerson testPerson:i]];
    }
    [XWDatabase saveModels:persons completion:^(BOOL isSuccess) {
        
    }];
}

实例化一堆对象, 调用 saveModels 方法。

二、删

1.删除一个模型
- (void)deleteModel
{
    XWPerson *person = [XWPerson new];
    person.cardID = @"1"; /// 指定想删除的主键(或联合主键)
    [XWDatabase deleteModel:person completion:^(BOOL isSuccess) {
        
    }];
}

实例化一个对象,为主键赋值(得知道删的是哪个,让她猜,臣妾做不到), 调用 deleteModel 方法。

2.删除此模型存储的所有数据
- (void)clearModel
{
    [XWDatabase clearModel:XWPerson.class completion:^(BOOL isSuccess) {

    }];
}

调用 clearModel 方法,传入想删除的模型类

3.选择性删除此模型存储的数据
/// 删除 age > 50 的数据
- (void)clearModel
{
    [XWDatabase clearModel:XWPerson.class condition:@"age > '50'" completion:^(BOOL isSuccess) {
        
    }];
}

调用 clearModel 方法,传入想删除的模型类和条件

三、改

1.更新某模型某个成员变量 (选择性更新)
/// 改名
- (void)updateModel
{
    XWPerson *person = [XWPerson new];
    person.cardID = @"2";
    person.name = @"新名字";
    
    /// 自定义成员变量更新
    [XWDatabase updateModel:person updatePropertys:@[@"name"] completion:^(BOOL isSuccess) {
        
   }];
    
}

实例化一个对象,为主键和有变化的成员变量赋值, 调用 updateModel 方法,传入想更新的成员变量名称。

2.更新某模型所有数据 (全量更新)
/// 根据传入的模型整体更新
- (void)updateModel
{
    XWPerson *person = [XWPerson new];
    person.cardID = @"2";
    person.name = @"新名字";
    person.girls = @[@"小妹",@"校花",@"小baby"];
    
    /// 整个模型更新
    [XWDatabase saveModel:person completion:^(BOOL isSuccess) {
        
    }];
    
}

实例化一个对象, 调用 updateModel 方法,传入想更新的模型。

四、查

1.根据主键查询模型
- (void)getOnePerson
{
    XWPerson *person = [XWPerson new];
    person.cardID = @"81";
    [XWDatabase getModel:person completion:^(XWPerson * obj) {
        
    }];
}

实例化一个对象,为主键赋值, 调用 getModel 方法。

2.查询数据库中所有该模型存储的数据
- (void)getModels
{
    [XWDatabase getModels:XWPerson.class completion:^(NSArray * _Nullable objs) {
        
        
    }];
}

调用 getModels 方法,传入模型类

3.查询数据库中所有该模型存储的数据 - 按某成员变量排序
/// 获取数据库中所有该模型存储的数据 - 按 age 字段降序排列
- (void)getModelsSortAge
{
    [XWDatabase getModels:XWPerson.class sortColumn:@"age" isOrderDesc:YES completion:^(NSArray * _Nullable objs) {
        
    }];
}

调用 getModels 方法,传入模型类和要排序的字段

4.查询数据库中所有该模型存储的数据 - 自定义查询条件
/// 获取数据库中所有该模型存储的数据 - 自定义查找条件 (例如模糊查询 name 含 学伟 的数据)
- (void)getModelsCondition
{
    [XWDatabase getModels:XWPerson.class condition:@"name like '%学伟'" completion:^(NSArray * _Nullable objs) {
        
    }];
}

调用 getModels 方法,传入模型类和查询的条件

5.查询数据库中所有该模型存储的数据 - 自定义查询条件并且可按照某字段排序
/// 获取数据库中所有该模型存储的数据 - 自定义查找条件可排序 (例如模糊查询 name 含 学伟 的数据, 并且按 age 升序排序)
- (void)getModelsConditionSort
{
    [XWDatabase getModels:XWPerson.class sortColumn:@"age" isOrderDesc:NO condition:@"name like '%学伟'" completion:^(NSArray * _Nullable objs) {
        
    }];
}

调用 getModels 方法,传入模型类和查询的条件和排序的成员变量名称

五、数据迁移

模型中成员变量发生变化,动态进行数据迁移
+ (void)initialize 
+ {
    [XWDatabase updateTable:self completion:^(BOOL isSuccess) {
        
    }];

在模型对象的 initialize 方法中 调用 updateTable 方法。之所以在 initialize 方法中调用是保证用户无感知的情况下在操作此模型进行数据操作时自动更新。

以上就是 XWDatabase V1.0 版本的所有功能示例。谢谢!

下面介绍一些使用规范和功能扩展。

六 、XWDatabaseModelProtocol 协议

/**
 主键 不可更改/唯一性
 
 @return 主键的属性名
 */
+ (NSString *)xw_primaryKey;

/**
 联合主键成员变量数组 (多个属性共同定义主键) - 优先级大于 'xw_primaryKey'

 @return 联合主键成员变量数组
 */
+ (NSArray < NSString * > *)xw_unionPrimaryKey;

/**
 自定义对象映射  (key: 成员变量名称 value: 对象类)

 @return 自定义对象映射
 */
+ (NSDictionary *)xw_customModelMapping;

/**
 忽略不保存数据库的属性
 
 @return 忽略的属性名数组
 */
+ (NSSet <NSString *>*)xw_ignoreColumnNames;

/**
 自定义字段名映射表 (默认成员变量即变量名, 可自定义字段名 key: 成员变量(属性)名称  value: 自定义数据库表字段名)

 @return 自定义字段名映射表
 */
+ (NSDictionary *)xw_customColumnMapping;

/**
 自定义表名 (默认属性类名)

 @return 自定义表名
 */
+ (NSString *)xw_customTableName;

当模型遵守 XWDatabaseModelProtocol 协议并选择性实现其中某些方法时她便会更好的为您服务。当然 主键 xw_primaryKey(或联合主键 xw_unionPrimaryKey )是查询和更新必须要实现的方法。

如果模型中成员变量存在其他的自定义模型,那其他的自定义模型需要遵从 NSCoding 协议并实现 initWithCoderencodeWithCoder 方法。 XWDatabase 中的 NSObject+XWModel 提供了一个宏可以快速使自定义对象具备归解档的功能 XWCodingImplementation

设计思路

  1. 根据 runtime 获取对象成员变量名称和类型生成 建表 SQL 语句
  2. 根据当前对象成员变量名称和原有数据库表中字段排序后进行比较,有差异进行数据迁移
  3. 根据模型动态生成 SQL 语句
  4. 利用事务进行大数据量的操作
  5. 创建一个保活的子线程(使异步线程的 Runloop 保持活跃)进行数据库操作,使用主线程队列保证数据操作的同步
  6. 数据库底层封装自 FMDB
  7. 创建一个单独存放图片二进制的库存储二进制文件。真实表中存储 二进制 文件的 hash 值已达到数据重用。

此库支持 CocoaPod 集成:

pod 'XWDatabase'

项目源码开源在 GitHub 中,链接: XWDatabase

作者:极客学伟
博客:https://blog.csdn.net/qxuewei/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容