Ric*_*kiG 13 cocoa-touch json objective-c ios
我正在尝试构建一个解析器/ 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];
}
Run Code Online (Sandbox Code Playgroud)
我这样做是因为我喜欢将这些可变值封装在它们引用的对象中.让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;
}
Run Code Online (Sandbox Code Playgroud)
所以我像这样给解析器/映射器发消息:
NSArray *objects = [ObjectParser parseData:self.responseData intoObjectsOfType:ObjectEntity.class];
Run Code Online (Sandbox Code Playgroud)
这意味着解析器必须知道我的根对象是什么,这很好,因为从Web服务检索它的对象当然具有这方面的知识.
上面只适用于没有嵌套对象的JSON,我一直在尝试构建解析器,以便它也将关系考虑在内,构建所需的对象并将它们插入到根对象中,这需要递归并且我保持陷入死胡同.
我想帮助我如何处理这个或任何见解,好像这样的东西作为一个库存在.也许是因为使用或者只是为了解决我遇到问题的部件.
先感谢您.
jaz*_*cat 10
考虑使用RestKit:http: //restkit.org
这个框架拥有您所需要的一切 - REST和JSON抽象,对象映射,甚至Core Data支持以及许多非常有用的东西,所有这些都以可定制和优雅的方式实现.
更新:好的,在编写另一种映射方法时,我决定不再这样做了,并做了一个小框架.它内省了对象的属性,并通过一些调整为您提供了免费的漂亮描述,isEqual/hashCode,免费的NSCoding支持,并允许生成/从JSON映射器生成(确实,实际上,NSDictionary,但谁会将其用于其他东西).所有NSNull检查,JSON中缺少的字段,JSON中的新意外字段都可以正常处理并正确报告.
如果有人希望这个共享给公众,你可以给我一些赞成或评论.我最终会这样做,但我可能会考虑更快地分享它.
为什么不为类添加映射?
+ (NSDictionary *)mapClasses {
return @{
@"category": [Category class],
// ...
};
}
Run Code Online (Sandbox Code Playgroud)
对于非容器属性,您甚至可以对属性进行运行时内省以避免冗余映射。
容器属性可以映射到特殊的包装对象:
[OMContainer arrayWithClass:Key.class], @"keys",
[OMContainer dicionaryWithKeyClass:ScopeID.class valueClass:Scope.class], @"possibleScopes",
Run Code Online (Sandbox Code Playgroud)
甚至是动态选择类型的块:
[OMDynamicType typeWithBlock:^(id obj){
if ([obj isKindOfClass:NSString.class] && [obj hasPrefix:@"foo"])
return Foo.class;
else
return Bar.class;
}], @"foo",
Run Code Online (Sandbox Code Playgroud)
实现这个可以像这样:
+ (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 */) {
// ...
}
}
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7380 次 |
| 最近记录: |