测试已测试 | ✓ |
语言语言 | Obj-CObjective C |
许可 | MIT |
发布上次发布 | 2016年2月 |
由Nick Donaldson,Michael Gorbach,Alex Rouse,Brian King,Rightpoint CI,Raiz Labs维护。
厌烦了编写样板代码来将反序列化 API 响应导入到模型对象中吗?
厌烦了处理数十个字符串键吗?
RZImport 正是为了帮助您而来!
RZImport 是一个在 NSObject
上的分类以及一个可选协议,用于在 iOS 应用中创建和更新模型对象。它特别适用于从 REST API 的反序列化 JSON HTTP 响应中导入对象,但也可以与任何需要转换为原生模型对象的 NSDictionary
或字典数组一起使用。
属性名称从同样命名的 NSDictionary
字符串键中推断出来,并在可能的情况下执行自动的类型转换。无需在每个地方引用字符串常量,只需使用与字典中键类似的方式进行属性命名,让 RZImport 为您处理。
RZImport 自动执行属性名称和键名称之间的不区分大小写的匹配,忽略下划线。例如,以下所有键都将映射到名为 firstName
的属性:
firstName
FirstName
first_name
FiRst_NAMe
您的属性名称无法与字典中的键同名?需要执行额外的验证或导入逻辑?没问题!RZImportable
协议提供了指定自定义映射、自定义导入逻辑和基于键的验证等功能的钩子。
键/属性映射只创建一次并缓存,因此一旦某个对象类型被导入一次,后续的导入会超级快速!
@interface Person : NSObject
@property (copy, nonatomic) NSNumber *ID;
@property (copy, nonatomic) NSString *firstName;
@property (copy, nonatomic) NSString *lastName;
@end
...
// Dictionary with some key/value pairs representing a person
NSDictionary *myDictionary = @{
@"id" : @100,
@"first_name" : @"Bob",
@"last_name" : @"Smith"
};
// Create a new Person instance by automatically inferring key/property mappings
Person *newPerson = [Person rzi_objectFromDictionary:myDictionary];
NSLog(@"ID: %@ Name: %@ %@", newPerson.ID, newPerson.firstName, newPerson.lastName);
ID: 100 Name: Bob Smith
只需将 Classes
目录中的文件复制到您的项目中,并将它们添加到您的目标中,然后就可以出发了!
注意:Private
目录包含不打算公开使用的私有头文件。
RZImport可以从字典或字典数组创建模型对象。
#import "NSObject+RZImport.h"
...
- (void)fetchThePeople
{
[self.apiClient get:@"/people" completion:^(NSData *responseData, NSError *error) {
if ( responseData ) {
NSError *jsonErr = nil;
id deserializedResponse = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:&jsonErr];
if ( deserializedResponse ) {
// convert to native objects
if ( [deserializedResponse isKindOfClass:[NSDictionary class]] ) {
Person *newPerson = [Person rzi_objectFromDictionary:deserializedResponse];
// ... do something with the person ...
}
else if ( [deserializedResponse isKindOfClass:[NSArray class]] ) {
NSArray *people = [Person rzi_objectsFromArray:deserializedResponse];
// ... do something with the people ...
}
}
else {
// Handle jsonErr
}
}
}];
}
您还可以从字典更新现有的对象实例。
Person *myPerson = self.person;
[myPerson rzi_importValuesFromDict:someDictionary];
如果您需要提供从字典键或键路径到属性名称的自定义映射,则在上面的模型类上实现《RZImportable》协议。自定义映射将优先于推断映射,但两者都可以用于同一类。
#import "RZImportable.h"
@interface MyModelClass : NSObject <RZImportable>
@property (copy, nonatomic) NSNumber *objectID;
@property (copy, nonatomic) NSString *zipCode;
@end
@implementation MyModelClass
+ (NSDictionary *)rzi_customKeyMappings
{
// Map dictionary key "zip" to property "zipCode"
// and dictionary key "id" to property "objectID"
return @{
@"zip" : @"zipCode",
@"id" : @"objectID"
};
}
@end
您还可以防止RZImport为特定的键导入值,或使用自己的自定义逻辑导入键的值。
- (BOOL)rzi_shouldImportValue:(id)value forKey:(NSString *)key;
{
if ( [key isEqualToString:@"zip"] ) {
// validation - must be a string that only contains numbers
if ( [value isKindOfClass:[NSString class]] ) {
return ([value rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location == NSNotFound);
}
return NO;
}
else if ( [key isEqualToString:@"address"] ) {
if ( [value isKindOfClass:[NSDictionary class]] ) {
// custom import logic
self.address = [Address rzi_objectFromDictionary:value];
}
return NO;
}
return YES;
}
如果您正在导入一个包含子字典的字典,这些子字典与您希望也使用RZImport导入的对象相对应,您可以在类上实现《RZImportable》协议,并返回rzi_nestedObjectKeys中的键。
@interface Job : NSObject
@property (copy, nonatomic) NSString *jobTitle;
@property (copy, nonatomic) NSString *companyName;
@end
@interface Person : NSObject <RZImportable>
@property (strong, nonatomic) Job *job;
@property (copy, nonatomic) NSString *firstName;
@end
@implementation Person
+ (NSArray *)rzi_nestedObjectKeys
{
return @[ @"job" ];
}
@end
...
- (void)createPersonWithJob
{
NSDictionary *personData = @{
@"firstName" : @"John",
@"job" : @{
@"jobTitle" : @"Software Developer",
@"companyName" : @"Raizlabs"
}
};
Person *p = [Person rz_objectFromDictionary:personData];
}
《RZImportable》还有一个方便的方法,您可以在类上实现以防止在使用《rzi_objectFromDictionary:》或《rzi_objectsFromArray:》时创建重复的对象。
+ (id)rzi_existingObjectForDict:(NSDictionary *)dict
{
// If there is already an object in the data store with the same ID, return it.
// The existing instance will be updated and returned instead of a new instance.
NSNumber *objID = [dict objectForKey:@"id"];
if ( objID != nil ) {
return [[DataStore sharedInstance] objectWithClassName:@"Person" forId:objID];
}
return nil;
}
当RZImport创建新对象实例时,它使用默认指定的初始化器`init`,因此它不能与需要其他指定初始化器的类直接使用。但是,为了解决这个问题,您可以在任何类上重写`+rzi_existingObjectForDict:`以确保始终返回使用正确初始化器(或现有对象)创建的新对象。
例如,RZImport不能直接用于创建《NSManagedObject》子类的有效实例,因为托管对象必须使用实体描述初始化。但是,没有理由它不能更新《NSManagedObject》子类从字典中或通过覆盖`+rzi_existingObjectForDict`以返回一个新对象,该对象已插入正确的托管对象上下文。
如果您对将RZImport与CoreData一起使用感兴趣,请查看《RZVinyl》。
RZImport遵从MIT许可证。请参阅《LICENSE》文件以获取详细信息。