RZImport 3.0.1

RZImport 3.0.1

测试已测试
语言语言 Obj-CObjective C
许可 MIT
发布上次发布2016年2月

Nick DonaldsonMichael GorbachAlex RouseBrian KingRightpoint CIRaiz Labs维护。



RZImport 3.0.1

厌烦了编写样板代码来将反序列化 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 目录包含不打算公开使用的私有头文件。

文档

最深入和最新的文档请阅读源代码中的Apple-doc注释头文件,或访问CocoaDocs上的文档页面。

基本使用

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》。

维护者

arrouse (@arrouse88)

nbonatsakis (@nickbona)

KingOfBrian (@KingOfBrian)

mattThousand (@mattThousand )

SpencerP

LFabien

贡献者

ndonald2 (@infrasonick)

许可证

RZImport遵从MIT许可证。请参阅《LICENSE》文件以获取详细信息。