对象映射库从JSON到NSObjects [英] Object Mapping library from JSON to NSObjects

查看:106
本文介绍了对象映射库从JSON到NSObjects的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我试图构建一个解析器/ objectMapper,它将为REST服务中使用的JSON构建Objective C对象。我从RestKit中获得了一些灵感让我的实体都拥有一个解码列表,告诉映射器哪些JSON键与哪些对象。像这样:

  // ObjectEntity实现
+(NSDictionary *)mapProperties {

/ *
localPropertiy - JSONProperty
* /

return @ {
@name:@name,
@category:@ category,
@possible_scopes:@possibleScopes,
@possible_descriptions:@possibleDescriptions,
@key:@keys
} ;

}

+(NSDictionary *)mapRelations {

return [NSDictionary dictionary];
}

我这样做是因为我喜欢这些可变值的封装在对象。



映射程序会执行这样的操作:

  +(NSArray *)parseData:(NSData *)jsonData intoObjectsOfType:(Class)objectClass {

//来自Web服务的解析器结果
NSError * error = nil;
CJSONDeserializer * deserializer = [CJSONDeserializer deserializer];
[deserializer setNullObject:nil];
NSArray * objects = [deserializer deserializeAsArray:jsonData error:& error];

NSMutableArray * result = [NSMutableArray array];

for(NSDictionary * o in objects){

id< EntityProtocol> entity = [[objectClass alloc] init];

NSDictionary * jsonKeys = objectClass.mapProperties;

for(NSString * key in jsonKeys.allKeys){

NSString * objectProperty = jsonKeys [key];
NSString * value = o [key];
if(value)
[entity setValue:value forKey:objectProperty];
}

[result addObject:entity];

}

return(NSArray *)result;
}

所以我给解析器/ mapper发送这样的消息:

  NSArray * objects = [ObjectParser parseData:self.responseData intoObjectsOfType:ObjectEntity.class]; 

这意味着解析器必须知道我的根对象是什么,从web服务当然有这个知识。



上面的只适用于JSON没有嵌套对象,我一直在试图构建解析器,以便它将采取的关系在构建需要的对象并将它们插入根对象时,这需要递归,并且我会继续运行到死胡同。



我想要一些帮助我怎么能接近这个或任何洞察力,好像这样的东西存在一个图书馆。



提前感谢。

解决方案

为什么不添加类的映射?

  +(NSDictionary *)mapClasses {
return @ {
@category:[Category class],
// ...
};
}

对于非容器属性,您甚至可以运行时反映属性,以避免多余的映射。



容器属性可以映射到特殊的包装器对象:

  [OMContainer arrayWithClass:Key.class ],@keys,
[OMContainer dicionaryWithKeyClass:ScopeID.class valueClass:Scope.class],@possibleScopes,

或者甚至是动态选择类型的块:

  [OMDynamicType typeWithBlock:^ ){
if([obj isKindOfClass:NSString.class]&& [obj hasPrefix:@foo])
return Foo.class;
else
return Bar.class;实现这可能会像: p>

  +(NSArray *)parseData:(NSData *)jsonData intoObjectsOfType:(Class)objectClass {
NSArray * parsed = * ... * /
NSMutableArray * decoded = [NSMutableArray array];
for(id obj in parsed){
[decoded addObject:[self decodeRawObject:parsed intoObjectOfType:objectClass]];
}
return decoding;
}

+(id)decodeRawObject:(NSDictionary *)dict intoObjectOfType:(Class)objectClass {
// ...
NSDictionary * jsonKeys = objectClass。 mapProperties;
NSDictionary * jsonClasses = objectClass.mapClasses;

for(NSString * key in jsonKeys.allKeys){
NSString * objectProperty = jsonKeys [key];
NSString * value = dict [key];
if(value){
id klass = jsonClasses [key];
if(!klass){
[entity setValue:value forKey:objectProperty];
} else if(klass == klass.class){
[entity setValue:[self decodeRawObject:value intoObjectOfType:klass]
forKey:objectProperty];
} else if(/ *检查容器和块* /){
// ...
}
}
}
//。 ..
}


I am trying to build a parser/objectMapper that will build Objective C objects for the JSON I consume from a REST service.

I took some inspiration from RestKit by having my Entities all hold a "decoding list" which tells a mapper which JSON keys goes with which objects. Like this:

//ObjectEntity implementation
+ (NSDictionary*) mapProperties {

    /*
     localPropertiy - JSONProperty
     */

    return @{
            @"name": @"name", 
            @"category": @"category", 
            @"possible_scopes": @"possibleScopes",
            @"possible_descriptions": @"possibleDescriptions",
            @"key": @"keys"            
     };

}

+ (NSDictionary*) mapRelations {

    return [NSDictionary dictionary];
}

I did so because I like the encapsulation of these changeable values to be in the object that they reference. Making the Mapper know as little as possible.

The mapper does something like this:

+ (NSArray*) parseData:(NSData*) jsonData intoObjectsOfType:(Class) objectClass {

    //Parser result from web service
    NSError *error = nil;
    CJSONDeserializer *deserializer = [CJSONDeserializer deserializer];
    [deserializer setNullObject:nil];
    NSArray *objects = [deserializer deserializeAsArray:jsonData error:&error];

    NSMutableArray *result = [NSMutableArray array];

    for (NSDictionary *o in objects) {

        id <EntityProtocol> entity = [[objectClass alloc] init];

        NSDictionary *jsonKeys = objectClass.mapProperties;

        for (NSString *key in jsonKeys.allKeys) {

            NSString *objectProperty = jsonKeys[key];
            NSString *value = o[key];
            if (value)
                [entity setValue:value forKey:objectProperty];
        }

        [result addObject:entity];

    }

    return (NSArray*)result;
}

So I message the parser/mapper like this:

NSArray *objects = [ObjectParser parseData:self.responseData intoObjectsOfType:ObjectEntity.class];

This means that the parser must know what my root object is, which is fine as the object retrieving it from the web service of course has this knowledge.

The above only works for JSON without nested objects, I have been trying to build the parser so that it will take the relationships into account as well, building the needed objects and inserting them into the root object, this needs to be recursive and I keep running into dead ends.

I would like some help to how I could approach this or any insight to as if something like this exists out as a library. Maybe for using or maybe just for tackling the parts I have problems with.

Thank you in advance.

解决方案

Why not add mappings for classes?

+ (NSDictionary *)mapClasses {
    return @{
            @"category": [Category class],
            // ...
    };
}

For non-container properties, you could even do runtime introspection of properties to avoid redundant mappings.

Container properties could map to special wrapper objects:

[OMContainer arrayWithClass:Key.class], @"keys",
[OMContainer dicionaryWithKeyClass:ScopeID.class valueClass:Scope.class], @"possibleScopes",

Or even blocks for dynamic selection of types:

[OMDynamicType typeWithBlock:^(id obj){
    if ([obj isKindOfClass:NSString.class] && [obj hasPrefix:@"foo"])
        return Foo.class;
    else
        return Bar.class;
}], @"foo", 

Implementing this could go something like:

+ (NSArray *)parseData:(NSData*)jsonData intoObjectsOfType:(Class)objectClass {
    NSArray *parsed = /* ... */
    NSMutableArray *decoded = [NSMutableArray array];
    for (id obj in parsed) {
        [decoded addObject:[self decodeRawObject:parsed intoObjectOfType:objectClass]];
    }
    return decoded;
}

+ (id)decodeRawObject:(NSDictionary *)dict intoObjectOfType:(Class)objectClass {
    // ...
    NSDictionary *jsonKeys = objectClass.mapProperties;
    NSDictionary *jsonClasses = objectClass.mapClasses;

    for (NSString *key in jsonKeys.allKeys) {
        NSString *objectProperty = jsonKeys[key];
        NSString *value = dict[key];
        if (value) {
            id klass = jsonClasses[key];
            if (!klass) {
                [entity setValue:value forKey:objectProperty];
            } else if (klass == klass.class) {
                [entity setValue:[self decodeRawObject:value intoObjectOfType:klass]
                          forKey:objectProperty];
            } else if (/* check for containers and blocks */) {
                // ...
            }
        }
    }
    // ...
}

这篇关于对象映射库从JSON到NSObjects的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆