CTXPropertyMapper 1.3.0

CTXPropertyMapper 1.3.0

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最新发布2017年6月

Mário Araújo 维护。



  • Mário Araújo 和 Stefan Ceriu 编写

简单的属性映射器,解决了最常见的数据解析问题。

  • 数据验证
  • 类型转换
  • 处理可选属性
  • 简单易用且高度可扩展

先决条件

CTXPropertyMapper 利用最近的 Objective-C 运行时新增功能,包括 ARC 和 blocks。它需要 iOS 6 或更高版本。

  • iOS 6 或更高版本。
  • OS X 10.7 或更高版本。

安装

要使用 CocoaPods 安装,请将以下行添加到您的项目 Podfile 中

pod 'CTXPropertyMapper'

使用示例

假设以下模型

@interface User : NSObject
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) BOOL active;
@property (nonatomic, strong) Job *job;
@property (nonatomic, strong) NSURL *profileURL;
@end

并接收以下 JSON 对象

{
	"avatarURL": "http://server.com/avatarurlpath",
	"firstName": "Jon",
	"lastName": "Snow",
	"origin": "Winterfell, The North, Westeros",
	"quote":"you know nothing Jon Snow (Ygritte)",
	"status":{
		"alive":true
	},
	"job": {
		"title":"The bastard of Winterfell",
		"sector":"Castle Black",
		"hours":"Full Time"
	}
}

则可以按如下方式配置属性映射器

CTXPropertyMapper *mapper = [[CTXPropertyMapper alloc] init];

[mapper addMappings:@{@"firstName":CTXProperty(firstName),
					  @"lastName":CTXProperty(lastName),
					  @"status.alive":CTXProperty(active)
					  }
		   forClass:[User class]];
  
//Decoding
NSArray *errors = nil;
User *user = [mapper createObjectWithClass:[User class] fromDictionary:dictionary errors:&errors];

//Encoding
NSDictionary *output = [mapper exportObject:user];

高级使用

CTXPropertyMapper 足够灵活,可以解析复杂和嵌套的对象。

CTXPropertyMapper *mapper = [[CTXPropertyMapper alloc] init];

//URL
CTXValueTransformerBlock decodeURL = ^id(NSString *input, NSString *propertyName){
	return [NSURL URLWithString:input];
};

CTXValueTransformerBlock encodeURL = ^id(NSURL *input, NSString *propertyName){
	return [input absoluteString];
};

//Origin
CTXValueConsumerBlock decodeOrigin = ^void(NSString *input, User *user){
	NSArray *originParts = [input componentsSeparatedByString:@","];
	if (originParts.count == 3) {
		user.origin = originParts[0];
		user.region = originParts[1];
		user.continent = originParts[2];	
	}
};

CTXValueGenerationBlock *encodeOrigin = ^id(id object){
	return [[user.origin, user.region, user.continent] componentsJoinedByString:@","];
};

[mapper addMappings:@{@"title":CTXProperty(title),
					  @"sector":CTXProperty(sector),
					  @"hours":CTXProperty(hours),
					  }
		   forClass:[Job class]];

[mapper addMappings:@{@"firstName":CTXProperty(firstName),
					  @"lastName":CTXProperty(lastName),
					  @"job":CTXClass(job, [Job class]),
					  @"avatarURL":CTXBlock(profileURL, encodeURL, decodeURL),
					  @"origin":CTXGenerationConsumerBlock(encodeOrigin, decodeOrigin)
					  }
		   forClass:[User class]];
			  
User *user = [mapper createObjectWithClass:[User class] fromDictionary:dictionary];

自定义工厂

CTXPropertyMapper 在内部使用默认对象初始化器,但某些技术(如 CoreData)需要自定义初始化器。为了支持这一点,您可以使用自己的自定义工厂实现 CTXPropertyMapperModelFactoryProtocol 协议。该工厂接收类类型和一个字典,以提高灵活性,允许使用已创建的模型,或从本地存储获取模型实例。

@interface CoreDataModelFactory : NSObject<CTXPropertyMapperModelFactoryProtocol>
- (instancetype)initWithContext:(NSManagedObjectContext *)context;
@end

@implementation CoreDataModelFactory
- (id)instanceForClass:(Class)class withDictionary:(NSDictionary *)dictionary
{
	NSEntityDescription *entity = [NSEntityDescription entityForName:[class description]] inManagedObjectContext:self.context];
	return [[NSManagedObjec alloc] initWithEntity:entity insertIntoManagedObjectContext:self.context];
}
@end

现在只是创建一个 CTXPropertyMapper 实例,并用您的自定义模型工厂进行初始化。

CTXPropertyMapper *mapper = [[CTXPropertyMapper alloc] initWithModelFactory:[[CoreDataModelFactory alloc] init]];

最终的编码器和解码器

CTXPropertyMapper 非常强大灵活,但不能解决所有问题。有时需要对编码或解码对象的最终版本进行改进。为了给开发者提供更多控制,我们引入了一个最终步骤钩子,即在对象由映射器返回之前,可以访问映射器的完整状态,且会运行。

[mapper setFinalMappingDecoder:^(NSDictionary *input, User *object){
    NSLog(@"[Warning] User non mapped keys %@", input);
} forClass:[User class] withOption:CTXPropertyMapperFinalMappingDecoderOptionExcludeAlreadyMappedKeys];
[mapper setFinalMappingEncoder:^(NSMutableDictionary *output, User *object){
    NSString *fullName = [NSString stringWithFormat:@"%@ %@", object.firstName, object.lastName];
    [output setValue:fullName forKey:@"fullName"];
} forClass:[User class]];

自动映射

通常客户模型的结构与服务器相同。为了避免重复代码,CTXPropertyMapper 支持自动创建模型。

CTXPropertyMapper *mapper = [[CTXPropertyMapper alloc] init]];

[mapper addMappings:[CTXPropertyMapper generateMappingsFromClass:[Job class]]
		   forClass:[Job class]];

我们使用一些 Objective-C 运行时调用创建有效的映射器,忽略指针地址、块、选择器等。当前支持的属性

  • NSString
  • NSNumber
  • char
  • double
  • enum
  • float
  • int
  • long
  • short
  • signed
  • unsigned

限制

映射生成不考虑通过协议继承的属性,或通过运行时动态创建的属性,因此请谨慎使用。

为了支持 keyPath 映射,CTXPropertyMapper 会将包含点(.)的所有键名称视为 keyPaths,并且不支持原本就包含点的键。

辅助工具

如果您的本地模型与远程模型共享属性名,但您不希望像自动映射那样映射整个对象,则可以使用方法 + (NSDictionary *)generateMappingsWithKeys:(NSArray *)keys,传入要映射的属性的数组。

CTXPropertyMapper *mapper = [[CTXPropertyMapper alloc] init]];

[mapper addMappings:[CTXPropertyMapper generateMappingsWithKeys:@[@"title", @"sector"]]
		   forClass:[Job class]];

验证

您可以为映射添加验证。

[mapper addMappings:[CTXPropertyMapper generateMappingsFromClass:[Job class]]
		   forClass:[Job class]];

如果需要,您可以创建自己的验证,通过查看类别 CTXPropertyDescriptor+Validators(h,m) 来获取灵感。

字符串

  • isRequired
  • matchesRegEx
  • length
  • minLength
  • maxLength
  • lengthRange
  • oneOf
  • equalTo

数字

  • min
  • max
  • range

许可证

CTXPropertyMapper 在 MIT 许可证下发布。有关详细信息,请参阅 LICENSE 文件。