对象映射库从JSON到NSObjects

如何解决对象映射库从JSON到NSObjects

| 我正在尝试构建一个解析器/ objectMapper,它将为我从REST服务使用的JSON构建目标C对象。 我从RestKit身上得到了一些启发,让我的实体都拥有一个\“解码列表\”,它告诉映射器哪些JSON键与哪些对象一起使用。像这样:
//ObjectEntity implementation
+ (NSDictionary*) mapProperties {

    /*
     localPropertiy - JSONProperty
     */

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

}

+ (NSDictionary*) mapRelations {

    return [NSDictionary dictionary];
}
我这样做是因为我喜欢将这些可变值封装在它们所引用的对象中。使Mapper尽可能少地了解。 映射器执行以下操作:
+ (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;
}
所以我像这样向解析器/映射器发送消息:
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:^(id obj){
    if ([obj isKindOfClass:NSString.class] && [obj hasPrefix:@\"foo\"])
        return Foo.class;
    else
        return Bar.class;
}],@\"foo\",
实施此操作可能类似于:
+ (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 */) {
                // ...
            }
        }
    }
    // ...
}
    ,考虑使用RestKit:http://restkit.org 该框架满足您的所有需求-REST和JSON抽象,对象映射,甚至Core Data支持以及许多真正有用的东西,所有这些都以可定制且优雅的方式实现。 更新:好的,在编写另一种映射方法时,我决定不再使用它,并做了一个小型框架。它内省了对象的属性,并进行了一些微调,为您提供了免费的漂亮说明,isEqual / hashCode,免费的NSCoding支持,并允许与JSON映射器生成(或从JSON映射器生成)(实际上,是NSDictionary,但谁可以将其用于其他用途) )。所有的NSNull检查,JSON中缺少的字段,JSON中新的意外字段都会得到妥善处理并正确报告。 如果有人希望将其分享给公众,您可以给我一些支持或评论。我最终会这样做,但我可能会考虑更快地共享它。     ,我也尝试过相同的方法。我的主要问题是准确描述类型。例如,对于嵌套数组,我使用了以下内容:
@{ @\"friends\" : @[[Person class]] }
但是事情变得混乱了,因为我需要为我想支持的不同类型发明越来越多的特殊语法。最后,我不再追求这种方法,而是寻求另一种解决方案-也是因为我需要进行的运行时检查使转换速度变慢。 现在有很多解决方案。我建议看看Awesome iOS网站。我还要指出JSON类生成器,因为它允许您 准确描述您的类型(包括日期等特殊映射器), 系统会自动检查类型(提供了报告的不匹配项和后备值), 您不需要花费时间来编写重复的代码(并且生成的代码似乎总是“工作正常”) 我讨厌做广告,但是这个工具为我节省了很多工作,因为我投入了我的应用程序的其他功能。出来似乎有点晚了,现在世界似乎已经切换到Swift了,但是还有更多的理由不浪费时间在Objective-C中编写模型。 以下是一些转换为JSON格式的代码示例:
// converting MyClass <-> NSDictionary
MyClass       *myClass = [MyClass myClassWithDict:someJsonDictionary];
NSDictionary *jsonDict = [myClass toDict];

// converting NSDictionary <-> NSData
NSDictionary *someJsonDictionary = [NSDictionary api_dictionaryWithJson:someJsonData];
NSData *jsonData = [someJsonDictionary api_toJson];
JSON类生成器还支持前面的注释中提到的功能:
-isEqual,-hash,-description,-copy,NSCoding/NSSecureCoding/NSKeyedArchiver
支持免费,并检查JSON响应中是否缺少/附加​​/ NSNull /可选字段和错误类型,报告错误,使用后备值正常失败,并使用方法分派而不是运行时类型自省(更快)进行此操作。     ,尝试CSMapper,真是太神奇了!您只需创建与类相同的名称,映射一些属性,然后就可以用一行代码轻松地将字典映射到您的对象。我已经在许多项目上对其进行了测试,发现它非常干净,高效。它使我能够灵活地在开发生命周期中轻松响应API更改。 https://github.com/marcammann/CSMapper 我目前正在更新文档,并在个人分叉上添加到项目中,希望可以将其合并:) https://github.com/AntonTheDev/CSMapper     ,我的建议是在NSObject上使用Motis类别。它重量轻,可以对您的对象类型执行自动验证,并且非常易于使用。 这个问题还有一个例子:在自定义对象中映射JSON对象 希望它是有用的。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-