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.
pod'JSONModel'github"jsonmodel/jsonmodel"- download the JSONModel repository
- copy the JSONModel sub-folder into your Xcode project
- link your app to SystemConfiguration.framework
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;
@endThere'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
idfrom string (in the JSON) to anintfor your class - copy the
countryvalue - convert
dialCodefrom a number (in the JSON) to anNSStringvalue - copy the
isInEuropevalue
All you have to do is define the properties and their expected types.
{
"id": 123,
"name": "Product name",
"price": 12.95
}@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString *name;
@property (nonatomic) float price;
@end{
"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{
"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;
@endNote: 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{
"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{
"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{
"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{
"id": 123,
"name": null
}@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@property (nonatomic) NSString <Ignore> *customProperty;
@end{
"id": null
}@interfaceProductModel : JSONModel@property (nonatomic) NSIntegerid;
@end@implementationProductModel
+ (BOOL)propertyIsOptional:(NSString *)propertyName
{
if ([propertyName isEqualToString:@"id"])
returnYES;
returnNO;
}
@endProductModel *pm = [ProductModel new];
pm.name = @"Some Name";
// convert to dictionaryNSDictionary *dict = [pm toDictionary];
// convert to jsonNSString *string = [pm toJSONString];@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@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@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;
}
@endMIT licensed - see LICENSE file.
We love pull requests! See CONTRIBUTING.md for full details.