Skip to content

Repository files navigation

JSONModel - Magical Data Modeling Framework for JSON

JSONModel allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS and tvOS apps. Automatic introspection of your model classes and JSON input drastically reduces the amount of code you have to write.

See CHANGELOG.md for details on changes.

Installation

CocoaPods

pod'JSONModel'

Carthage

github"jsonmodel/jsonmodel"

Manual

  1. download the JSONModel repository
  2. copy the JSONModel sub-folder into your Xcode project
  3. link your app to SystemConfiguration.framework

Basic Usage

Consider you have JSON like this:

{ "id": 10, "country": "Germany", "dialCode": 49, "isInEurope": true }
  • create a JSONModel subclass for your data model
  • declare properties in your header file with the name of the JSON keys:
@interfaceCountryModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *country;
@property (nonatomic) NSString *dialCode;
@property (nonatomic) BOOL isInEurope;
@end

There's no need to do anything in the implementation (.m) file.

  • initialize your model with data:
NSError *error;
CountryModel *country = [[CountryModel alloc] initWithString:myJson error:&error];

If the validation of the JSON passes. you have all the corresponding properties in your model populated from the JSON. JSONModel will also try to convert as much data to the types you expect. In the example above it will:

  • convert id from string (in the JSON) to an int for your class
  • copy the country value
  • convert dialCode from a number (in the JSON) to an NSString value
  • copy the isInEurope value

All you have to do is define the properties and their expected types.

Examples

Automatic name based mapping

{
"id": 123,
"name": "Product name",
"price": 12.95
}
@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *name;
@property (nonatomic) float price;
@end

Model cascading (models including other models)

{
"orderId": 104,
"totalPrice": 13.45,
"product": {
"id": 123,
"name": "Product name",
"price": 12.95
}
}
@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *name;
@property (nonatomic) float price;
@end@interfaceOrderModel : JSONModel@property (nonatomic) NSInteger orderId;
@property (nonatomic) float totalPrice;
@property (nonatomic) ProductModel *product;
@end

Model collections

{
"orderId": 104,
"totalPrice": 103.45,
"products": [
{
"id": 123,
"name": "Product #1",
"price": 12.95
},
{
"id": 137,
"name": "Product #2",
"price": 82.95
}
]
}
@protocol ProductModel;
@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *name;
@property (nonatomic) float price;
@end@interfaceOrderModel : JSONModel@property (nonatomic) NSInteger orderId;
@property (nonatomic) float totalPrice;
@property (nonatomic) NSArray <ProductModel> *products;
@end

Note: the angle brackets after NSArray contain a protocol. This is not the same as the Objective-C generics system. They are not mutually exclusive, but for JSONModel to work, the protocol must be in place.

Also property can have generics info for compiler

@interfaceOrderModel : JSONModel@property (nonatomic) NSInteger orderId;
@property (nonatomic) float totalPrice;
@property (nonatomic) NSArray<ProductModel *> <ProductModel> *products;
@end

Nested key mapping

{
"orderId": 104,
"orderDetails": {
"name": "Product #1",
"price": {
"usd": 12.95
}
}
}
@interfaceOrderModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *productName;
@property (nonatomic) float price;
@end@implementationOrderModel
+ (JSONKeyMapper *)keyMapper
{
return [[JSONKeyMapper alloc] initWithModelToJSONDictionary:@{
@"id": @"orderId",
@"productName": @"orderDetails.name",
@"price": @"orderDetails.price.usd"
}];
}
@end

Map automatically to snake_case

{
"order_id": 104,
"order_product": "Product #1",
"order_price": 12.95
}
@interfaceOrderModel : JSONModel@property (nonatomic) NSInteger orderId;
@property (nonatomic) NSString *orderProduct;
@property (nonatomic) float orderPrice;
@end@implementationOrderModel
+ (JSONKeyMapper *)keyMapper
{
return [JSONKeyMapper mapperForSnakeCase];
}
@end

Optional properties (i.e. can be missing or null)

{
"id": 123,
"name": null,
"price": 12.95
}
@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString <Optional> *name;
@property (nonatomic) float price;
@property (nonatomic) NSNumber <Optional> *uuid;
@end

Ignored properties (i.e. JSONModel completely ignores them)

{
"id": 123,
"name": null
}
@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString <Ignore> *customProperty;
@end

Making scalar types optional

{
"id": null
}
@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@end@implementationProductModel
+ (BOOL)propertyIsOptional:(NSString *)propertyName
{
if ([propertyName isEqualToString:@"id"])
returnYES;
returnNO;
}
@end

Export model to NSDictionary or JSON

ProductModel *pm = [ProductModel new];
pm.name = @"Some Name";
// convert to dictionaryNSDictionary *dict = [pm toDictionary];
// convert to jsonNSString *string = [pm toJSONString];

Custom data transformers

@interfaceJSONValueTransformer (CustomTransformer)
@end@implementationJSONValueTransformer (CustomTransformer)
- (NSDate *)NSDateFromNSString:(NSString *)string
{
NSDateFormatter *formatter = [NSDateFormatternew];
formatter.dateFormat = APIDateFormat;
return [formatter dateFromString:string];
}
- (NSString *)JSONObjectFromNSDate:(NSDate *)date
{
NSDateFormatter *formatter = [NSDateFormatternew];
formatter.dateFormat = APIDateFormat;
return [formatter stringFromDate:date];
}
@end

Custom getters/setters

@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *name;
@property (nonatomic) float price;
@property (nonatomic) NSLocale *locale;
@end@implementationProductModel
- (void)setLocaleWithNSString:(NSString *)string
{
self.locale = [NSLocalelocaleWithLocaleIdentifier:string];
}
- (void)setLocaleWithNSDictionary:(NSDictionary *)dictionary
{
self.locale = [NSLocalelocaleWithLocaleIdentifier:dictionary[@"identifier"]];
}
- (NSString *)JSONObjectForLocale
{
return self.locale.localeIdentifier;
}
@end

Custom JSON validation

@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *name;
@property (nonatomic) float price;
@property (nonatomic) NSLocale *locale;
@property (nonatomic) NSNumber <Ignore> *minNameLength;
@end@implementationProductModel
- (BOOL)validate:(NSError **)error
{
if (![supervalidate:error])
returnNO;
if (self.name.length < self.minNameLength.integerValue)
{
*error = [NSErrorerrorWithDomain:@"me.mycompany.com"code:1userInfo:nil];
returnNO;
}
returnYES;
}
@end

License

MIT licensed - see LICENSE file.

Contributing

We love pull requests! See CONTRIBUTING.md for full details.

About

Magical Data Modeling Framework for JSON - allows rapid creation of smart data models. You can use it in your iOS, macOS, watchOS and tvOS apps.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages