GithubHelp home page GithubHelp logo

ctxpropertymapper's Introduction

CTXPropertyMapper

Simple property mapper that solves the most common parsing problems.

  • Data Validation
  • Type conversion
  • Handle optional properties
  • Simple to use and highly extensible

Prerequisites

CTXPropertyMapper takes advantage of recent Objective-C runtime additions, including ARC and blocks. It requires:

  • iOS 6 or later.
  • OS X 10.7 or later.

Installing

To install using CocoaPods add the following line to your project Podfile:

pod 'CTXPropertyMapper'

Example of usage

Assuming the following model:

@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

and receiving the following json object:

{
	"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"
	}
}

the property mapper can be configured like so:

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];

Advanced usage

CTXPropertyMapper is flexible enough to parse complex and nested objects.

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];

Custom Factory

CTXPropertyMapper uses the default object initializer internally, but some technologies like CoreData require a custom initializer. To support that you can use your own custom Factory implementing the protocol CTXPropertyMapperModelFactoryProtocol. The factory receives the class type and a dictionary for added flexibility, allowing the use of already created models, or fetching model instance from the local storage.

@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

Now just create your instance of CTXPropertyMapper initializing with your custom model factory.

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

Final Encoders and Decoders

CTXPropertyMapper is very powerful and flexible, but cannot solve every single problem. Sometimes refinements on the final version of the encoded or decoded objects are necessary. To give developers more control we introduced a final step hook the that gives access to the full mapper state and is run right before the object is returned by the mapper.

[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]];

Automatic Mappings

Usually the client model has the same structure as the server. To avoid repetitive code, CTXPropertyMapper supports creating models automatically.

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

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

We use some objective c runtime calls to create a valid mapper, ignoring pointer address, blocks, selectors, etc. Currently supported properties:

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

Limitations

Mapping generation doesn't consider inherited properties, created through protocols or dynamically created through the runtime, so use it wisely.

To support keyPath mappings, the CTXPropertyMapper considers all key names containing dots (.) as keyPaths, and does not support keys that originally contain dots.

Helpers

If your local model shares property names with the remote model, but you don't want to map the whole object like the automatic mapping does, you can use the method + (NSDictionary *)generateMappingsWithKeys:(NSArray *)keys, passing the array of properties that you want to map.

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

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

Validations

You can add validations to your mappings.

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

If necessary, you can create your own validations, get inspired by looking at the category CTXPropertyDescriptor+Validators(h,m).

Strings

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

Numbers

  • min
  • max
  • range

License

CTXPropertyMapper is released under a MIT License. See LICENSE file for details.

ctxpropertymapper's People

Contributors

dmakarenko avatar mariobajr avatar sathran avatar stefanceriu avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.