从 JSON 到 NSObjects 的对象映射库
我正在尝试构建一个解析器/objectMapper,它将为我从 REST 服务使用的 JSON 构建 Objective 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];
}
我这样做是因为我喜欢将这些可变值封装在它们引用的对象中。让映射器知道得尽可能少。
映射器执行如下操作:
+ (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,我一直在尝试构建解析器,以便它也考虑到关系,构建所需的对象并将它们插入到根对象中,这需要是递归的,我保留陷入死胡同。
我想要一些帮助来帮助我如何处理这个问题或任何见解,就好像这样的东西作为图书馆存在一样。也许是为了使用,或者也许只是为了解决我遇到问题的部分。
先感谢您。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
考虑使用 RestKit:http://restkit.org
这个框架拥有您需要的一切 — REST 和 JSON 抽象、对象映射,甚至核心数据支持和许多真正有用的东西,全部以可定制和优雅的方式实现。
更新:好吧,在编写另一个映射方法时,我决定不能再这样做了,于是做了一个小框架。它内省对象的属性,并通过一些调整为您提供免费的漂亮描述、isEqual/hashCode、免费的 NSCoding 支持,并允许生成到 JSON 映射器或从 JSON 映射器生成(好吧,实际上是 NSDictionary,但谁会把它用于其他用途)。所有 NSNull 检查、JSON 中缺失的字段、JSON 中新的意外字段都会得到妥善处理并正确报告。
如果有人希望将其分享给公众,您可以给我一些点赞或评论。我最终会这样做,但我可能会考虑更快地分享。
Consider using RestKit: http://restkit.org
This framework has all you need — REST and JSON abstractions, object mapping, even Core Data support and a lot of really useful stuff, all implemented in a customizable and elegant manner.
UPDATE: Ok, while writing yet another mapping method, I decided I can't do it anymore and done a small framework. It introspects object's properties, and with a little tuning gives you free pretty description, isEqual/hashCode, free NSCoding support, and allows generating to/from JSON mappers (ok, actually, NSDictionary, but who would use it for something else). All NSNull-checks, missing fields in JSON, new unexpected fields in JSON are handled gracefully and reported properly.
If anybody wants this shared to the public, you could give me some upvotes or comments. I'd do that eventually, but I might consider sharing it faster.
为什么不为类添加映射?
对于非容器属性,您甚至可以进行 运行时自省属性以避免冗余映射。
容器属性可以映射到特殊的包装对象:
甚至是用于动态选择类型的块:
实现它可以是这样的:
Why not add mappings for classes?
For non-container properties, you could even do runtime introspection of properties to avoid redundant mappings.
Container properties could map to special wrapper objects:
Or even blocks for dynamic selection of types:
Implementing this could go something like:
我也尝试了同样的方法。我的主要问题是准确描述类型。例如,对于嵌套数组,我使用了这样的东西:
但事情变得混乱,因为我需要为不同类型发明越来越多的特殊语法,我想支持它们。最后,我不再追求这种方法,而是寻求另一种解决方案 - 也是因为我需要执行的运行时检查减慢了转换速度。
现在有很多解决方案。我建议您查看 Awesome iOS 网站。我还想指出 JSON 类生成器,因为它允许您
我讨厌打广告,但是这个该工具为我节省了很多工作,我将这些工作投入到应用程序的其他功能中。它的出现有点晚了,现在世界似乎正在转向 Swift,但更有理由不浪费时间在 Objective-C 中编写模型。
以下是一些转换为 JSON 的代码示例:
JSON 类生成器:
免费支持,并检查 JSON 响应中是否缺少/附加/NSNull/可选字段和错误类型,报告错误,使用回退值优雅地失败,并使用方法分派而不是运行时类型自省(更快)来执行此操作。
I tried the same approach also. My main problem was, to describe the types accurately. For example for nested arrays I used something like this:
But things became messy, because I needed to invent more and more special syntax for different types, that I wanted to support. In the end I stopped pursuing this approach and went for another solution - also because the runtime checks I needed to do were slowing the transformation down.
There are a lot of solutions out there right now. I would suggest to have a look at Awesome iOS website. And I also would like to point out JSON Class Generator, because it allows you to
I hate to advertise, but this tool saved me a lot of work, that I invested into other features of my apps. It came out a little late, now that the world seems to switch to Swift, but even more reason to not waste time on writing models in Objective-C.
Here are some code examples converting to/form JSON:
The features mentioned in a previous comment are also supported by JSON Class Generator:
support for free and does check for missing/additional/NSNull/optional fields and wrong types in the JSON response, reports errors, gracefully fails with fallback values and does this using method dispatch rather than runtime type introspection (which is faster).
尝试一下CSMapper,太棒了!您只需创建与类同名的 plist,映射一些属性,然后您可以使用一行代码轻松地将字典映射到您的对象。我在很多项目上测试过它,发现它非常干净、高性能。它使我能够灵活地轻松响应开发生命周期中的 API 更改。
https://github.com/marcammann/CSMapper
我目前正在更新文档并添加到项目中在个人分叉上,希望很快就会合并:)
https://github.com/AntonTheDev/CSMapper
Try out CSMapper, it is amazing! You just create plists named the same as the class, map some properties, then you can map a dictionary to your objects with ease with a single line of code. I have tested it on many projects and found it to be very clean, performant. It gave me flexibility to respond to API changes during the development lifecycle with ease.
https://github.com/marcammann/CSMapper
I am currently updating the documentation and adding on to the project on a personal fork which should hopefully be merged soon :)
https://github.com/AntonTheDev/CSMapper
我的建议是在 NSObject 上使用 Motis 类别。它是轻量级的,对您的对象类型执行自动验证,并且使用起来非常简单。
在另一个问题中有一个例子: 在自定义对象中映射 JSON 对象< /a>
希望它有用。
My recommendation is to use the Motis category on NSObject. It is light-weight, performs automatic validation to your object types and very simple to use.
There is an exapmle in this other question: Mapping JSON objects in custom objects
Hope it is useful.