KeyValueObjectMapping 是一个 Cocoa 框架,它提供了一个简单的方法来处理任何键/值类型,例如 JSON、XML、plist,甚至是常见的 NSDictionary。无需额外的框架。
它旨在与解析器一起使用,例如:NSJSONSerialization、JSONKit、NSXMLParser 和其他资源,主要目标是避免在处理键/值类型时需要进行的繁琐工作。
JSON、XML、plist 或简单的 NSDictionary。NSDictionary 上的键同名,一切都将自动完成。DCCustomInitialize 和 DCCustomParser。DCObjectMapping 将任何键映射到不遵守约定的特定属性。DCArrayMapping 来告知将要插入的具体元素类型。DCPropertyAggregator 将值聚合到特定属性。NSDate 或如果它是以毫秒形式(自1970年1月1日起的UNIX 时间戳)在 JSON 中发送的,则无需额外配置即可进行解析。NSURL 的属性,则框架将尝试使用 [NSURL URLWithString:] 方法将值作为 NSString 传递。使用 CocoaPods,这是在 Objective-C 世界中管理依赖项的最简单方法。
使用 iOS-Universal-Framework 由于 KeyValueObjectMapping 使用 iOS-Universal-Framework 来构建和编译项目,您可以轻松地将 iOS-Universal-Framework 生成的 .framework 拖入您的应用程序中,导入头文件 DCKeyValueObjectMapping.h 并开始使用该框架。
#import <KeyValueObjectMapping/DCKeyValueObjectMapping.h>KeyValueObjectMapping 是一个简单的对象,您需要做的就是创建一个新的对象,然后将一个字典转换为任何类。
假设您有一些像这样的 JSON
{
"id_str": "27924446",
"name": "Diego Chohfi",
"screen_name": "dchohfi",
"location": "São Paulo",
"description": "Instrutor na @Caelum, desenvolvedor de coração, apaixonado por música e cerveja, sempre cerveja.",
"url": "http://about.me/dchohfi",
"protected": false,
"created_at": "Tue Mar 31 18:01:12 +0000 2009"
}您的 User 模型看起来像这样
@interface User : NSObject
@property(nonatomic, strong) NSString *idStr;
@property(nonatomic, strong) NSString *name;
@property(nonatomic, strong) NSString *screenName;
@property(nonatomic, strong) NSString *location;
@property(nonatomic, strong) NSString *description;
@property(nonatomic, strong) NSURL *url;
@property(nonatomic, strong) BOOL protected;
@property(nonatomic, strong) NSNumber *followersCount;
@property(nonatomic, strong) NSDate *createdAt;
@end使用任何 JSON 解析器,您需要将这个 NSString 转换为 NSDictionary 表示形式
NSError *error;
NSDictionary *jsonParsed = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers error:&error];如果您不使用 KeyValueObjectMapping,则需要创建一个 User 类型的实例,并在字典上设置与属性名称相同的所有属性。并在需要时将其转换。
User *user = [[User alloc] init];
[user setIdStr: [jsonParsed objectForKey: @"id_str"]];
[user setName: [jsonParsed objectForKey: @"name"]];
[user setScreenName: [jsonParsed objectForKey: @"screen_name"]];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.datePattern = @"eee MMM dd HH:mm:ss ZZZZ yyyy";
NSDate *date = [formatter dateFromString:@"Sat Apr 14 00:20:07 +0000 2012"];
[user setCreatedAt: date];枯燥的工作,不是吗?所以,如果您使用 KeyValueObjectMapping,您只需要提供字典和要创建的类,其余的都将自动完成。
DCKeyValueObjectMapping *parser = [DCKeyValueObjectMapping mapperForClass: [Tweet class]];
Tweet *tweet = [parser parseDictionary:jsonParsed];
NSLog(@"%@ - %@", tweet.idStr, tweet.name);如果您的 NSDate 模式与默认模式不同,默认模式为 @"eee MMM dd HH:mm:ss ZZZZ yyyy",则可以配置为使用不同的模式。因此,有一个对象可以向框架添加自定义配置。
使用 DCParserConfiguration,可以更改某些组件的默认行为,例如解析日期的默认模式。
DCParserConfiguration *config = [DCParserConfiguration configuration];
config.datePattern = @"dd/MM/yyyy";
DCKeyValueObjectMapping *parser = [DCKeyValueObjectMapping mapperForClass: [Tweet class] andConfiguration: config];如果您的 JSON 有一些特定的键不匹配属性名称,则可以使用 DCObjectMapping 将此键映射到属性,属性类型也可以是特定的对象。
您的 Tweet 模型
@interface Tweet : NSObject
@property(nonatomic, readonly) NSString *idStr;
@property(nonatomic, readonly) NSString *tweetText;
@property(nonatomic, readonly) User *userOwner;
@end并且收到的 JSON 符合以下结构
{
"id_str": 190957570511478800,
"text": "Tweet text",
"user": {
"name": "Diego Chohfi",
"screen_name": "dchohfi",
"location": "São Paulo"
}
}使用 DCObjectMapping,可以解析这个 JSON 并像这样覆盖键名
DCParserConfiguration *config = [DCParserConfiguration configuration];
DCObjectMapping *textToTweetText = [DCObjectMapping mapKeyPath:@"text" toAttribute:@"tweetText" onClass:[Tweet class]];
DCObjectMapping *userToUserOwner = [DCObjectMapping mapKeyPath:@"user" toAttribute:@"userOwner" onClass:[Tweet class]];
[config addObjectMapping:textToTweetText];
[config addObjectMapping:userToUserOwner];
DCKeyValueObjectMapping *parser = [DCKeyValueObjectMapping mapperForClass: [Tweet class] andConfiguration:config];
Tweet *tweetParsed = [parser parseDictionary:json];NSArray 属性由于Objective-C不支持像Java和其他静态语言那样的类型化集合,我们无法确定集合中元素的类型。但是,可以配置键值对象映射(KeyValueObjectMapping),以便了解将在类的特定属性中添加到集合的元素类型。
因此,如果模型User有许多推文
@interface User : NSObject
@property(nonatomic, strong) NSString *idStr;
@property(nonatomic, strong) NSString *name;
@property(nonatomic, strong) NSString *screenName;
@property(nonatomic, strong) NSString *location;
@property(nonatomic, strong) NSString *description;
@property(nonatomic, strong) NSURL *url;
@property(nonatomic, strong) BOOL protected;
@property(nonatomic, strong) NSNumber *followersCount;
@property(nonatomic, strong) NSDate *createdAt;
@property(nonatomic, strong) NSArray *tweets;
@end那么推文看起来是
@interface Tweet : NSObject
@property(nonatomic, strong) NSString *idStr;
@property(nonatomic, strong) NSString *text;
@property(nonatomic, strong) NSDate *createdAt;
@end并且JSON看起来是
{
"id_str": "27924446",
"name": "Diego Chohfi",
"screen_name": "dchohfi",
"location": "São Paulo",
"description": "Instrutor na @Caelum, desenvolvedor de coração, apaixonado por música e cerveja, sempre cerveja.",
"url": "http://about.me/dchohfi",
"protected": false,
"created_at": "Tue Mar 31 18:01:12 +0000 2009",
"tweets" : [
{
"created_at" : "Sat Apr 14 00:20:07 +0000 2012",
"id_str" : 190957570511478784,
"text" : "Tweet text"
},
{
"created_at" : "Sat Apr 14 00:20:07 +0000 2012",
"id_str" : 190957570511478784,
"text" : "Tweet text"
}
]
}使用DCArrayMapping并将其添加到配置中,您就可以告诉KeyValueObjectMapping如何解析特定的属性。
DCArrayMapping *mapper = [DCArrayMapping mapperForClassElements: :[Tweet class] forAttribute:@"tweets"] onClass:[User class]];
DCParserConfiguration *config = [DCParserConfiguration configuration];
[config addArrayMapper:mapper];
DCKeyValueObjectMapping *parser = [[DCKeyValueObjectMapping mapperForClass:[User class] andConfiguration:configuration];
User *user = [parser parseDictionary:jsonParsed];有时你面临的解析JSON没有权限修改结构体,并且你不想使你的类遵循特定的结构体。使用DCPropertyAggregator,你可以将一个键值聚合到你的领域模型的特定属性上。
因此,如果你的JSON看起来像这样
{
"tweet" : "Some text",
"latitude" : -23.588453,
"longitude" : -46.632103,
"distance" : 100
}如果你遵循这个JSON结构,你的对象不会那么有组织,对吗?所以,你可以使你的对象遵循不同的结构
@interface Tweet : NSObject
@property(nonatomic, readonly) NSString *text;
@property(nonatomic, readonly) Location *location;
@end
@interface Location : NSObject
@property(nonatomic, readonly) NSNumber *distance;
@property(nonatomic, readonly) Point *point;
@end
@interface Point : NSObject
@property(nonatomic, readonly) NSNumber *latitude;
@property(nonatomic, readonly) NSNumber *longitude;
@end并且使用DCPropertyAggregator来映射这个特定的行为
DCPropertyAggregator *aggregteLatLong = [DCPropertyAggregator aggregateKeys:[NSSet setWithObjects:@"latitude", @"longitude", nil] intoAttribute:@"point"];
DCPropertyAggregator *aggregatePointDist = [DCPropertyAggregator aggregateKeys:[NSSet setWithObjects:@"point", @"distance", nil] intoAttribute:@"location"];
DCParserConfiguration *configuration = [DCParserConfiguration configuration];
[configuration addAggregator:aggregteLatLong];
[configuration addAggregator:aggregatePointDist];
DCKeyValueObjectMapping *parser = [DCKeyValueObjectMapping mapperForClass:[Tweet class] andConfiguration:configuration];
Tweet *tweet = [parser parseDictionary: json];