daikiri 1.9.15

daikiri 1.9.15

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布时间上次发布2024年2月

Jordi Puigdellivol 维护。



daikiri 1.9.15

Daikiri

描述

这是一个轻量级且简洁的库,用于处理模型,允许 JSON 到 Model 到 Core Data 的双向转换。对于服务器/应用程序同步非常有用。

安装

使用 pods

pod 'daikiri'

使用说明

创建一个继承自Daikiri的模型,并添加你想要自动转换的属性。注意,如果`submodels`也继承了Daikiri,它们也将自动转换。

JSON

#import "Daikiri.h"
#import "Headquarter.h"

@interface Hero : Daikiri

@property (strong,nonatomic) NSString* name;
@property (strong,nonatomic) NSNumber* age;
@property (strong,nonatomic) Headquarter* headquarter;

@end

然后你可以这样做

NSDictionary* d = @{
    @"name" : @"Batman",
    @"age"  : @10,
    @"headquarter":@{
        @"address" : @"patata",
        @"isActive" : @1,
        @"vehicles"   : @[
            @{@"model" : @"Batmobile"},
            @{@"model" : @"Batwing"},
            @{@"model" : @"Tumbler"},
        ]
    }
};

Hero * model = [Hero fromDictionary:d];    

然后转换回

NSDictionary* modelToDict = [model toDictionary];
NSLog(@"Model to dict: %@",modelToDict);

你也可以将数组转换为类,为此您需要创建方法-(Class)property_DaikiriArray,其中`property`是`NSArray`属性的名称。

在前面的例子中,我们有如下的模型Headquarter

@interface Headquarter : Daikiri

@property(strong,nonatomic) NSString* address;
@property(strong,nonatomic) NSNumber* isActive;
@property(strong,nonatomic) NSArray*  vehicles;

@end

使用以下方法

-(Class)vehicles_DaikiriArray{
    return [Vehicle class];
}

车辆将自动转换。

核心数据

设置

Daikiri提供了一个CoreData管理器。它创建`managedObjectContents`并连接到名为`yourprojectname.sqlite`的数据库,数据库位于`applicationDocumentsDirectory`。

您可以通过设置DaikiriCoreData管理器的`databaseName`属性来更改项目名称

[DaikiriCoreData manager].databaseName = @"youdatabasename";

应该在其他的任何CoreData调用之前执行这个调用,因此推荐在`didFinishLaunchingWithOptions`中进行设置。

您只需在您的应用代理的 -(void)applicationWillTerminate:(UIApplication *)application 方法中添加对 [[DaikiriCoreData manager] saveContex] 的调用即可,即使发生崩溃也能保存上下文。

但是,您也可以通过在您的模型中覆写 +(NSManagedObjectContext*)managedObjectContext 函数来自定义 CoreData 管理器。

+(NSManagedObjectContext*)managedObjectContext{
    NSManagedObjectContext *context = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
    return context;
}
测试

Daikiri 提供了一种非常简单的方法,可以在每个测试中设置一个完整的清洁测试数据库,这样您就可以无故障地进行单元测试。它还在每个测试中使用事务,所以每次测试都会回滚,数据库在每次测试后都保持清洁。

只需将这些添加到您的测试的 setUptearDown 方法中即可。

    - (void)setUp {
        [super setUp];
        [[DaikiriCoreData manager] useTestDatabase:YES];
        [[DaikiriCoreData manager] beginTransaction];
    }

    - (void)tearDown {
        [super tearDown];
        [[DaikiriCoreData manager] rollback];
    }

Core数据模型

使用 Daikiri 模型,我们可以在类似记录的方式中与 coredata 进行交互。您只需将模型的名称与数据库中相同 .xcdatamodeld

一个 Daikiri 模型有一个 id 属性,这是用于所有后续方法的 主键

然后您可以这样做

[model create] //It creates a new record in the database needs to have the id

model.name = "Bruce wayne";
model.age  = @10;

[model save]    //Updates the record saved in the database (if it doesn't exists, it will create it)

我们还可以

// Get an specific hero
Hero* batman = [Hero find:@10]; //Search the model in the database
[batman delete];                //Deletes it from the database

// Get all heros
NSArray* allHeros = [Hero all];    

如果您愿意,还有一些方便的快捷方式可以直接从字典中执行这些基本操作

+(bool)createWith:(NSDictionary*)dict;
+(bool)updateWith:(NSDictionary*)dict;    
+(bool)deleteWith:(NSNumber*)id;

关系

除了 findall,当您的模型在数据库中时,您有不同的方式来访问它们的关系

belongsTohasManybelongsToMany

请查看下面的示例以了解它们

//Add models to database
Hero * batman               = [Hero createWith:@{@"id":@1, @"name":@"Batman"         ,@"age":@49}];
Hero * spiderman            = [Hero createWith:@{@"id":@2, @"name":@"Spiderman"      ,@"age":@19}];
Hero * superman             = [Hero createWith:@{@"id":@3, @"name":@"Superman"       ,@"age":@99}];

Enemy* luxor                = [Enemy createWith:@{@"id":@1, @"name":@"Luxor"          ,@"age":@32}];
Enemy* greenGoblin          = [Enemy createWith:@{@"id":@2, @"name":@"Green Goblin"   ,@"age":@56}];
Enemy* joker                = [Enemy createWith:@{@"id":@4, @"name":@"Joker"          ,@"age":@45}];

Friend* robin               = [Friend createWith:@{@"id":@1, @"name":@"Robin"         ,@"hero_id":batman.id}];
Friend* maryJane            = [Friend createWith:@{@"id":@2, @"name":@"Mary Jane"     ,@"hero_id":spiderman.id}];
Friend* blackCat            = [Friend createWith:@{@"id":@3, @"name":@"Black cat"     ,@"hero_id":spiderman.id}];

EnemyHero* luxorBatman      = [EnemyHero createWith:@{@"id":@1, @"hero_id":batman.id      ,@"enemy_id":luxor.id, @"level":@7}];
EnemyHero* luxorSuperman    = [EnemyHero createWith:@{@"id":@2, @"hero_id":superman.id    ,@"enemy_id":luxor.id, @"level":@5}];
EnemyHero* jokerBatman      = [EnemyHero createWith:@{@"id":@3, @"hero_id":batman.id      ,@"enemy_id":joker.id, @"level":@10}];
EnemyHero* greenGoblinSpider= [EnemyHero createWith:@{@"id":@4, @"hero_id":spiderman.id   ,@"enemy_id":greenGoblin.id, @"level":@10}];


NSLog(@"Robin's hero is: %@",robin.hero.name);      //Belongs to

for(Friend* friend in spiderman.friends){           //has many
    NSLog(@"Spiderman friend: %@",friend.name);
}

for(Enemy* enemy in batman.enemies){                //Belongs to many
    NSLog(@"Batman enemy: %@ with level: %@",enemy.name, ((EnemyHero*)enemy.pivot).level);
}

查询构建器

我们有一个 QueryBuilder 来创建自定义查询,你可以做诸如以下操作

EnemyHero * enemyHero = [[EnemyHero.query
                            where:@"hero_id"  is:batman.id]
                            where:@"enemy_id" is:joker.id]
                        .first;

NSArray * heroes = [[Hero.query 
                        where:@"id" operator:@">" value:@2] 
                        orderBy:@"age"]
                    .get;

for(Hero * hero in heroes){
    NSLog(@"Hero: %@",hero.name);
}

如果你的类名使用前缀(两个字符),而你的实体没有,你可以覆盖 usesPrefix 函数以返回 true。这将移除在查询数据库时的前缀。

工厂

Daikiri 类库提供了一个类似 Laravel 的工厂类,用于测试。你可以拥有你的工厂来创建测试对象,使每个测试看起来非常整洁。

使用方法

首先创建一个工厂类,包含简单的 registerFactories 方法,并通过提供一个简单的字典创建工厂。

@implementation HeroFactory

+(void)registerFactories{

    [DKFactory define:Hero.class builder:^NSDictionary *{
        return @{
            @"name": @"Batman",
            @"age" : @"49"
        };
    }];

    [DKFactory define:Enemy.class builder:^NSDictionary *{
        return @{
            @"name": @"Luxor",
            @"age" : @"32"
        };
    }];
}
工厂状态

你可以定义不同类型的类,可以用另一个名字(它会合并默认的和新定义的)。

+(void)registerFactories{

    [DKFactory define:Hero.class builder:^NSDictionary *{
        return @{
            @"name": @"Batman",
            @"age" : @"49"
        };
    }];

    [DKFactory define:Hero.class name:@"old" builder:^NSDictionary *{
        return @{
            @"age" : @"100"
        };
    }];
}

然后在测试类的 setup 方法中调用 [Yourfactory registerFactories]

之后,在你的测试中,你可以通过简单的调用来实例化任何类

    Hero* testHero   = [factory(Hero.class)  make];
    Enemy* testEnemy = [factory(Enemy.class) create];

注意,make 只创建对象,而不会将其存储到数据库中,但 create 会存储到数据库。

您可以使用非宏构造函数来获取更多选项。

    NSArray* oldHerosArray = [[DKFactory factory:Hero.class name:@"old" count:4] make];
关系

工厂中令人兴奋的一点是,您可以使用回调来创建关系,因此您可以像这样操作

    [DKFactory define:Headquarter.class builder:^NSDictionary *{
        return @{
            @"name": @"Star tower",
            @"hero_id" : ^{
                return ((Daikiri*)[factory(Hero.class) create]).id;
            }
        };
    }];

并且英雄(Hero)只会在实例化对象为makecreate时被创建,不错吧?