测试已测试 | ✗ |
Lang语言 | Obj-CObjective C |
许可证 | 自定义 |
释放上次发布 | 2014年12月 |
由Matt York,Matt York,Ben Gordon维护。
这是一个 NSObject 的嵌入类别,使得从 JSON 或 XML(包括 SOAP)初始化自定义对象变得简单,并将这些对象反序列化为 JSON/XML。它仅需要一点设置——然后您就再也不必为每个自定义 NSObject 创建自己的序列化和初始化方法了。
版本 2.0
唯一的一步是将 NSObject+ObjectMap.{h,m} 添加到您的项目中。就是这样。
创建您的对象
这一步需要了解返回的 JSON 将是什么样子。检查您的数据源,并创建与之一致的自定义 NSObject 类。例如,假设您的 JSON 返回如下
{
Username : "Big Al",
Password : "r0llt1d3",
Color : "Crimson",
Location : "Tuscaloosa, AL",
Championships: 15
}
如果是这种情况,您将创建这样一个自定义 NSObject,它的属性与之匹配
@property (nonatomic, retain) NSString *Username;
@property (nonatomic, retain) NSString *Password;
@property (nonatomic, retain) NSString *Color;
@property (nonatomic, retain) NSString *Location;
@property (nonatomic, retain) NSNumber *Championships;
这个类的好处在于,它不仅限于基本的 Objective-C 类(如 NSString 和 NSNumber),还可以处理您创建的任何对象。让我们把前面的类定义称为 User
——现在让我们创建一个具有 User 类对象属性的实例。
// JSON snippet
{
Name : "Bryant-Denny",
CreatedByUser : {
Username : "Big Al",
Password : "r0llt1d3",
Color : "Crimson",
Location : "Tuscaloosa, AL",
Championships: 15
}
}
// Place.h
@property (nonatomic, retain) NSString *Name;
@property (nonatomic, retain) User *CreatedByUser;
NSObject+ObjectMap
通过反序列化 JSON 并将 JSON 包中的各种键与您想要映射的对象的各种属性相匹配来工作。这种设计的一个限制是,您必须将属性命名为与返回的键完全相同,否则该属性在反序列化完成后将保持未初始化(nil)。
处理数组
不幸的是,在使用 JSON 时,您对封装在数组中的对象的类型一无所知。为了将 JSON 反序列化到 NSObject,还需要进行一个额外的设置步骤。如果您的自定义 NSObject 包含一个或多个 NSArray,您需要为该对象创建一个自定义的 init 方法(或者把以下代码包括在您已经创建的自定义 init 中)。这个方法创建了一个名为 propertyArrayMap
的 NSDictionary,其中的键/值对将属性名称(键)与其想要为 NSArray 包含的对象类型(值)相匹配。当对象从您的 JSON 数据包创建时,其正在处理该属性是 NSArray,它将检查这个字典来找出它需要在数组中创建哪种类型的对象。以下是一个配置示例:
// JSON snippet
{
Name : "Billy",
FavoriteColors : ["Red","Blue","Tangerine"],
FavoritePeople : [{
Name : "Jenny",
FavoriteColors: [@"Orange","Black"],
FavoritePeople: []
},{
Name : "Ben",
FavoriteColors: ["Silver","Emerald","Aquamarine"],
FavoritePeople: []
}]
}
// Person.h
@property (nonatomic, retain) NSString *Name;
@property (nonatomic, retain) NSArray *FavoriteColors;
@property (nonatomic, retain) NSArray *FavoritePeople;
// Person.m
-(id)init {
self = [super init];
if (self) {
[self setValue:@"NSString" forKeyPath:@"propertyArrayMap.FavoriteColors"];
[self setValue:@"Person" forKeyPath:@"propertyArrayMap.FavoritePeople"];
}
return self;
}
在这个例子中,我们有一个表示 Person 的 JSON 字符串。这个人有一个名字和两个数组特性,FavoriteColors 和 FavoritePeople。FavoriteColors 是一个字符串数组,FavoritePeople 是 Person 对象的数组。如您所见,为 Person.m 中创建的定制 init 方法设置了 propertyArrayMap
,以处理应包含的对象类型(在 setValue 中)及其对应的键(forKeyPath)。与其他提到的属性和键一样,请确保它们拼写正确,以便正确反序列化和对象创建。
从 JSON 到对象
此时,您应该已经创建了自定义的 NSObjects,并且从 webservice 返回了 JSON 数据,可以直接将其转换成这些对象。现在,简单部分来了。使用内置的 NSJSONSerialization 方法将 JSON 数据转换成 NSDictionary 或 NSArray,然后将这些传递到一个方法中,该方法会从这些数据返回您的自定义 NSObject。我们将使用前面提到的 Person JSON 片段来说明这一点。
// JSON snippet
{
Name : "Billy",
FavoriteColors : ["Red","Blue","Tangerine"],
FavoritePeople : [{
Name : "Jenny",
FavoriteColors: [@"Orange","Black"],
FavoritePeople: []
},{
Name : "Ben",
FavoriteColors: ["Silver","Emerald","Aquamarine"],
FavoritePeople: []
}]
}
// Turn that JSON into an NSDictionary, then into your Person object
// - jsonData is the NSData equivalent of the JSON snippet above.
NSData *jsonData;
// Now to create the Person object
Person *newPerson = [[Person alloc] initWithJSONData:jsonData];
使用数组的方式几乎完全相同,但是在 JSON 反序列化返回的是 NSArray 而不是 NSDictionary。如果这个 NSArray 包含许多 Person 对象,请使用以下方法创建这个数组。
NSArray *peopleArray = [NSObject arrayOfType:[Person class] fromJSONData:jsonData];
将对象序列化为 JSON
大多数现代的 web 服务和 API 使用 JSON postfix 数据来传递可以在服务器端处理的对象。使用这个类创建您的 JSON 数据就像吸管吸水一样简单。
Person *newPerson = [[Person alloc] init];
NSData *jsonData = [newPerson JSONData];
要查看 JSON 数据包的字符串表示,请使用返回 NSString 而不是 NSData 的 [NSObject JSONString]
方法。您可以使用在线的验证工具(如 jsonlint.com)来确保这是一个有效的 JSON。
故障排除
由于前面列出的约束条件,以下是一些要检查和考虑的事项,如果类不像预期的那样工作:
propertyArrayMap
键/值,并且命名正确。创建您的对象
这一步需要了解将返回的 XML 将是什么样子。检查您的数据源,并创建匹配这些的自定义 NSObject 类。例如,假设您返回的 XML 看起来像这样:
<MyObject>
<Username>Big Al</Username>
<Password>r0llt1d3</Password>
<Color>Crimson</Color>
<Location>Tuscaloosa, AL</Location>
<Championships>15</Championships>
<MyObject>
如果是这种情况,您将创建一个名为 MyObject
的自定义 NSObject,其属性与这些相匹配。
@property (nonatomic, retain) NSString *Username;
@property (nonatomic, retain) NSString *Password;
@property (nonatomic, retain) NSString *Color;
@property (nonatomic, retain) NSString *Location;
@property (nonatomic, retain) NSNumber *Championships;
序列化和反序列化
就像 JSON 一样,XML 支持嵌套的复杂对象。也不需要指定数组类型,因此处理 XML 可以说是更简单。要将对象序列化为 XML,只需做以下操作:
MyObject *object = [[MyObject alloc] init];
//*** Fill in object properties with data here ***
NSData *xmlData = [object XMLData];
//*** Send data over web ***
从 XML 反序列化回对象同样简单。
// XML String of Object
NSString *xmlString = @"<MyObject>
<Username>Big Al</Username>
<Password>r0llt1d3</Password>
<Color>Crimson</Color>
<Location>Tuscaloosa, AL</Location>
<Championships>15</Championships>
<MyObject>";
// XML Data
NSData *xmlData = [xmlString dataUsingEncoding:NSUTF8StringEncoding];
// Create MyObject
MyObject *customObject = [[MyObject alloc] initWithXMLData:xmlData];
关于SOAP的说明: 目前仅支持简单的、基于标签的SOAP。如有需要,将支持更复杂的空间命名和属性处理。如果您发现处理更复杂SOAP的出色方法,请随时提交pull request。
在NSObject+ObjectMap.h
文件中有两个# define 常量,表示NSDate反序列化的格式/时区信息。将这些常量与您获取的JSON/XML关联起来,以确保NSDateFormatter正确地创建NSDate对象。这些属性是:
要查看NSObject+ObjectMap的实际效果,请检查顶层Demos
文件夹中的我们的许多样本Xcode项目中的一个。Google Places演示展示了NSObject+ObjectMap对JSON的处理,而Weather演示则负责XML。在运行之前,请务必查看它们的README以了解任何设置工作。
我们有全新的单元测试套件以确保ObjectMap在对其进行任何更改后仍然有效。您可以通过在Tests文件夹下打开UnitTests.xcodeproj
来运行它。只需按下键盘上的Cmd - U
即可运行,并在屏幕上查看是否显示了“Tests Succeeded”。有时它会显示“Tests Failed”,但如果您查看每个TestCase类,您会看到每个方法旁边都有绿色或红色的钻石。绿色钻石表示成功,红色钻石表示失败。
版权所有(c)2012阿拉巴马大学董事会所有权利保留。
允许以源代码和二进制形式重新分发和使用,无论是否修改,只要满足以下条件:
本软件按“原样”提供,并且不考虑明示的保证或建议性保证,包括但不限于适销性和适用于特定用途的隐含保证。在任何情况下,版权所有者或贡献者不对因使用本软件而产生的任何直接、间接、意外、特殊、示范性或后果性损害(包括但不限于替代商品或服务的采购;使用、数据或利润的损失;或业务中断)承担责任,无论索赔是由于何种原因,基于何种责任理论,无论是基于合同、严格责任还是侵权(包括疏忽或其他),即使是已知存在此类损害的风险。