测试已测试 | ✓ |
语言语言 | Obj-CObjective C |
许可证 | MIT |
发布上次发布 | 2017年12月 |
由 Krzysztof Zablocki,Krzysztof Zabłocki 维护。
数据解析是我们需要在应用中执行的最常见任务之一,但仍有大多数人在手动进行解析,重复编写相同的代码来映射每个类。
通常的解析需要以下步骤
有一些库可以帮助完成这项工作,例如 Mantle、RESTKit 以及更多……但我想要一个自包含的、易于更改/删除且不需要太多代码的库。
我在对 Foldify 进行开发时创建了 Property Mapper,这是一个简单的自包含解决方案,允许您指定数据之间的映射,这些数据是你接收到的,以及在您的应用中的数据表示……还有一些附加功能,如 类型包装、验证。
我不喜欢传递 JSON,因此我在自带的 NSDictionary/NSArray 对象上编写解析。
如果您以 JSON 的形式得到数据,只需编写一个简单的分类,将 JSON 转换为原生对象即可使用 NSJSONSerialization。
假设您有一个这样的对象
@interface TestObject : NSObject
@property(nonatomic, strong) NSURL *contentURL;
@property(nonatomic, strong) NSURL *videoURL;
@property(nonatomic, strong) NSNumber *type;
@property(nonatomic, strong) NSString *title;
@property(nonatomic, strong) NSString *uniqueID;
@end
并且您从服务器以这种格式收到数据
@{
@"videoURL" : @"http://test.com/video.mp4",
@"name" : @"Some Cool Video",
@"videoType" : [NSNull null],
@"sub_object" : @{
@"title" : @616,
@"arbitraryData" : @"data"
}
}
这是您在解析代码中会编写的代码
[KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:@{
@"videoURL" : KZBox(URL, contentURL),
@"name" : KZProperty(title),
@"videoType" : KZProperty(type),
@"sub_object" : @{
@"title" : KZProperty(uniqueID)
}
}];
很明显它在做什么,但如果您不明白,它将把 videoURL 字符串转换为 contentURL NudeURL 对象,它还将从 sub_object 中获取标题并将其赋给 uniqueID。它还处理 NSNull。
现在,让我们换个主意,决定我们的类型属性应该是 typedef 枚举,使用 KZPropertyMapper 来实现这一点非常简单,将类型映射更改为以下内容并添加以下方法
@"videoType" : KZCall(videoTypeFromString:, type),
//! implemented on instance you are parsing
- (id)videoTypeFromString:(NSString *)type
{
if ([type isEqualToString:@"shortVideo"]) {
return @(VideoTypeShort);
}
return @(VideoTypeLong);
}
如果您需要在使用选择器时传递属性名,只需在 KZCall 中传递一个两个参数的选择器。第二个参数将是作为 NSString 传递的属性名。
@"video" : KZCall(objectFromDictionary:forPropertyName:, type),
//! implemented on instance you are parsing
- (id)objectFromDictionary:(NSDictionary *)dictionary forPropertyName:(NSString *)propertyName
{
Class objectClass = [self classForProperty:propertyName];
id object = [objectClass new];
[object updateFromDictionary:dictionary];
return object;
}
完成。KVC 还应该负责将 NSNumber 转换为 int,如果您的属性使用基本类型。相同的方法也适用于子对象实例或您可以分配给属性的任何东西。
您还可以在映射之前验证服务器数据
[KZPropertyMapper mapValuesFrom:dictionary toInstance:self usingMapping:@{
@"videoURL" : KZBox(URL, contentURL).isRequired().min(10),
@"name" : KZProperty(title).lengthRange(5, 12),
@"videoType" : KZProperty(type),
@"sub_object" : @{
@"title" : KZProperty(uniqueID),
},
}];
验证器可以连接在一起,您可以指定任意多的验证器用于每个字段,验证在映射之前发生在源数据上。
如果验证失败,mapValues 将返回 NO 作为结果,并且您可以使用扩展方法获取验证错误列表。
任何验证错误都将阻止映射,因为数据可能已损坏,我们不希望得到部分更新的数据。
如果您需要更多,您可以在KZPropertyDescriptor上添加验证类别,查看示例代码,它非常简单。
如果您的数据是以数组而不是字典的形式提供给您,您也可以这样做。
sourceData = @{@"sub_object_array" : @[@"test", @123]}
@{@"sub_object_array" : @{@1 : KZProperty(uniqueID)}
这将从sub_object_array中获取第一个项并将其分配给uniqueID。这也适用于递归。
您可以轻松地在整个应用程序中扩展装箱功能,只需在KZPropertyMapper中添加实现此类方法的功能即可
+ (id)boxValueAsType:(id)value
{
//! your boxing
}
现在您可以在代码中任何地方使用 @type 映射。
@{
@"videoURL" : KZList(
KZBoxT(object, URL, contentURL),
KZPropertyT(object, uniqueID),
KZCallT(object, passthroughMethod:, type)
)
}
由 Marek Cirkos 贡献
这些更改的实施由 The App Business 赞助。
使用CocoaPods:将以下行添加到您的 Podfile
pod "KZPropertyMapper"
使用Carthage:将其添加到您的 Cartfile
github "krzysztofzablocki/KZPropertyMapper" "master"
或者直接将 KZPropertyMapper/
文件夹添加到您的项目中,确保启用这些文件上的ARC。