WAMapping 0.0.8

WAMapping 0.0.8

测试已测试
language语言 Obj-CObjective C
许可证 MIT
发布最后发布2017年8月

Marian Paul维护。



WAMapping 0.0.8

  • 作者:
  • Marian Paul

ipodishima开发并维护,他是Wasappli Inc的创始人兼首席技术官。

Wisembly赞助

从JSON到NSObject的快速映射器

  • [x] 快速
  • [x] 易于编写和阅读
  • [x] 节省您许多时间
  • [x] 支持JSON与NSObject的双向转换
  • [x] 可定制
  • [x] 内置CoreData、NSCoding和内存存储
  • [x] 内置插入或更新对象
  • [x] 已通过测试

访问wiki了解更多关于WAMapping高级使用的详细信息。

WAMapping是一个iOS库,可以将字典转换为对象,将对象转换为字典。它的目标是简化手动解析数据和为对象分配值的大括号模板代码。当涉及到使用CoreData时,尤其是由于插入或更新操作,它变得更困难。我还没有提到它所涉及的性能。WAMapping为您解决了这个问题!

安装和使用

设置映射关系

在典型用途中,source被称作服务器响应转换为字典,而destination被称作应用值的对象目标,例如一个NSManagedObject

让我们假设以下Enterprise

@interface Enterprise : NSObject

@property (nonatomic, strong) NSNumber *itemID;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSDate *creationDate;
@property (nonatomic, strong) NSNumber *streetNumber;
@property (nonatomic, strong) NSArray *employees; // Can be mutable, or an `NSSet` or an `NSOrderedSet`
@property (nonatomic, strong) NSArray *chiefs;

@end

itemID是在存储中标识你的对象。这不是必需的,但推荐使用,以避免创建重复项。

假设有以下JSON

{
    "id": 1,
    "name": "Wasappli",
    "creation_date": "2013-10-01",
    "address": {
        "street_number": 5149
    }
}

映射看起来如下:

WAEntityMapping *enterpriseMapping = [WAEntityMapping mappingForEntityName:@"Enterprise"];
enterpriseMapping.identificationAttribute = @"itemID";

// Add the classic attributes
[enterpriseMapping addAttributeMappingsFromDictionary:@{
                                                        @"id": @"itemID",
                                                        @"name": @"name",
                                                        @"address.street_number": @"streetNumber"
                                                        }];      
                                                   
// Map custom values. Here an `NSDate` from a string using an `NSDateTransformer`
[enterpriseMapping addMappingFromSourceProperty:@"creation_date"
                          toDestinationProperty:@"creationDate"
                                      withBlock:^id(id value) {
                                          return [dateFormatter dateFromString:value];
                                      }
                                   reverseBlock:^id(id value) {
                                       return [dateFormatter stringFromDate:value];
                                   }];

// Register the mapping for future use
WAMappingRegistrar *registrar = [WAMAppingRegistrar new];
[registrar registerMapping:enterpriseMapping];
// [registrar registerMapping:employeeMapping];
// WAEntityMapping *savedEnterpriseMapping = [registrar mappingForEntityName:@"Enterprise"];

这样就完成了...!

使用映射器

首先,创建一个存储。这是必需的步骤。我在此仓库提供了三种存储方式:

  • WAMemoryStore,它依赖于简单的NSMutableSet
  • WANSCodingStore,使用NSCoding协议保存对象,
  • WACoreDataStore,利用CoreData

如果你想要使用SQLite,例如,你可以轻松地创建自己的存储,查看wiki。

WAMemoryStore *store = [[WAMemoryStore alloc] init];

// or
// WACoreDataStore *store = [[WACoreDataStore alloc] initWithManagedObjectContext:localContext];

// or
// WANSCodingStore *store = [[WANSCodingStore alloc] initWithArchivePath:archivePath];

然后,使用存储分配一个映射器

WAMapper *mapper = [[WAMapper alloc] initWithStore:store];

最后,将字典表示映射到对象

[mapper mapFromRepresentation:json
                      mapping:enterpriseMapping
                   completion:^(NSArray *mappedObjects) {
                       firstEnterprise = [mappedObjects firstObject];
                   }];

就这样解决了!

添加关系

WAMapping也支持关系

  • 经典关系
{
    "id": 1,
    "first_name": "Marian",
    "enterprise": {
        "id": 1,
        "name": "Wasappli",
        "creation_date": "2013-10-01",
        "address": {
            "street_number": 5149
        }
    }
}
WARelationshipMapping *enterpriseRelationship = 
[WARelationshipMapping relationshipMappingFromSourceProperty:@"enterprise" toDestinationProperty:@"enterprise" withMapping:enterpriseMapping];
[employeeMapping addRelationshipMapping:enterpriseRelationship];
  • 使用识别属性
{
    "enterprise": {
        "id": 1,
        "name": "Wasappli",
        "creation_date": "2013-10-01",
        "address": {
            "street_number": 5149
        },
        "chiefs": 1 # Could also be [1, 2, 3] 
    },
    "employees": [{
                  "id": 1,
                  "first_name": "Marian"
                  }]
}
WARelationshipMapping *chiefsRelationship = [WARelationshipMapping relationshipMappingFromSourceIdentificationAttribute:@"chiefs" toDestinationProperty:@"chiefs" withMapping:employeeMapping];
[enterpriseMapping addRelationshipMapping:chiefsRelationship];

反向映射器

此库还包含了一个反向映射器。它支持从对象到字典的反向转换。

WAReverseMapper *reverseMapper = [[WAReverseMapper alloc] init];

json = [reverseMapper reverseMapObjects:enterprises
                            fromMapping:enterpriseMapping
                  shouldMapRelationship:nil];

默认映射

如果您有一个返回相同格式的所有日期的服务器,那么您只需让映射器或反向映射器转换一次即可。

而不是编写

[enterpriseMapping addAttributeMappingsFromDictionary:@{
                                                        @"id": @"itemID",
                                                        @"name": @"name",
                                                        @"address.street_number": @"streetNumber"
                                                        }];      
                                                   
// Map custom values. Here an `NSDate` from a string using an `NSDateTransformer`
[enterpriseMapping addMappingFromSourceProperty:@"creation_date"
                          toDestinationProperty:@"creationDate"
                                      withBlock:^id(id value) {
                                          return [dateFormatter dateFromString:value];
                                      }
                                   reverseBlock:^id(id value) {
                                       return [dateFormatter stringFromDate:value];
                                   }];

您将编写

[enterpriseMapping addAttributeMappingsFromDictionary:@{
                                                        @"id": @"itemID",
                                                        @"name": @"name",
                                                        @"address.street_number": @"streetNumber",
                                                        @"creation_date": @"creationDate"
                                                        }];


id(^toDateMappingBlock)(id ) = ^id(id value) {
    if ([value isKindOfClass:[NSString class]]) {
        return [dateFormatter dateFromString:value];
    }
    
    return value;
};

[mapper addDefaultMappingBlock:toDateMappingBlock
           forDestinationClass:[NSDate class]];

同样的事情也发生在反向映射器上。请注意,如果您为特定的属性(如只有年份的日期)提供自定义映射在NSDate对象上,您可以将属性添加到实体映射中,这将覆盖默认行为。

进度和取消

Both WAMapperWAReverseMapper 支持NSProgress。请注意,Apple 明确在其有关NSProgressReporting(我们在其中模仿)的文档中指出,采用此协议的对象通常会“一次性的”,这意味着您应该为每个映射操作使用一个 WAMapper

进度

您可以使用以下小块代码跟踪进度。请注意,进度会计算映射的主顶级对象(如果您的数组中有一个包含千个对象的关系,进度不会反映映射的千个子对象)。这是因为选择之前在iOS 9之前采用子进度不是很好。

[mapper.progress addObserver:self
                  forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                     options:NSKeyValueObservingOptionNew
                     context:NULL];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(fractionCompleted))] && [object isKindOfClass:[NSProgress class]]) {
        NSLog(@"Mapping progress = %f", [change[@"new"] doubleValue]);
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

取消

您可以使用以下代码取消映射或反向映射。请注意,要发生取消,您必须从其他线程调用映射!

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    [mapper mapFromRepresentation:JSON mapping:employeeMapping completion:^(NSArray *mappedObjects, NSError *error) {
        NSLog(@"Mapped objects %@ - Error %@", mappedObjects, error);
    }];
});

[mapper.progress cancel];

备注

待办事项

  • [ ]与流行的映射器基准对比
  • [ ]为键路径处理添加更多测试,特别是在关系上

灵感

您可以从RestkitFastEasyMapping中获得灵感。这两个都是我在项目上使用过的库,但存在问题。

#贡献:问题、建议、Pull Requests?

如果您遇到特定于WAAppRouting的问题,请在此打开新问题。

对于新功能的pull requests,我们鼓励并非常重视!请尽量与现有代码风格保持一致。如果您正在考虑对项目进行重大更改或添加,请在打开新问题之前询问,以便有机会合并。

#到此为止!

  • 如果您满意,请不要犹豫向我发送一条推文@ipodishima
  • 在MIT许可下分发。
  • facebook上关注Wasappli