I have a slightly complex nested JSON object that I need to map to Objective-C class. One think I need to do is skip levels in JSON when mapping. Here is what I mean:
I want to map the following JSON Dictionary:
NSDictionary *JSONDictionary = #{
#"status" : #"PASSWORD_EXPIRED",
#"_embedded" : #{
#"user" : #{
#"id" : #"00ub0oNGTSWTBKOLGLNR",
#"profile" : #{
#"login" : #"isaac#example.org",
#"firstName" : #"Isaac",
#"lastName" : #"Brock",
#"locale" : #"en_US",
#"timeZone" : #"America/Los_Angeles"
}
}
}
};
to
#interface Authentication : MTLModel <MTLJSONSerializing>
#property (strong, nonatomic) NSDate* expiresAt;
#property (strong, nonatomic) NSString* status;
#property (strong, nonatomic) NSString* relayState;
#property (strong, nonatomic) NSString* sessionToken;
#property (strong, nonatomic) NSString* stateToken;
//Embeded Resources
#property (strong, nonatomic) User* user;
#end
As you can see I am not creating an object for "_embeded". I am skipping it and mapping user to a User object.
Can this be achieved? If so How?
I have tried this in the implementation but it did not work:
#implementation Authentication
+ (NSDictionary*)JSONKeyPathsByPropertyKey {
return #{
#"expiresAt" : #"expiresAt",
#"status" : #"status",
#"sessionToken" : #"sessionToken",
#"stateToken" : #"stateToken",
#"relayState" : #"relayState",
#"user" : #"_embeded/user",
};
}
+ (NSValueTransformer *)userJSONTransformer {
return [NSValueTransformer mtl_JSONDictionaryTransformerWithModelClass:User.class];
}
#end
I used to do it with the following code:
+ (NSValueTransformer *)userJSONTransformer {
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSDictionary *userDict) {
return [MTLJSONAdapter modelOfClass:[User class] fromJSONDictionary:userDict error:nil];
} reverseBlock:^id(User *user) {
return [MTLJSONAdapter JSONDictionaryFromModel:user];
}];
}
And also in +JSONKeyPathsByPropertyKey I think it should be #"user" : #"_embeded.user"
Related
Well this is bizarre and I can't find any explanation.
The issue is that I am "transforming" a object property to a value into a NSDictionary and in a specific value it "encodes" a "special character" but on other values it doesn't.
This is the .h file for the object where I declare the properties:
#import <CoreLocation/CoreLocation.h>
#import "ModelObject.h"
#interface CheckinObject : ModelObject
#property (nonatomic,strong) NSString *name;
#property (nonatomic,strong) NSString *num;
#property (nonatomic,strong) NSString *date;
This is the .m file, where I synthesize and put it into a NSDictionary:
#implementation CheckinObject
#synthesize name;
#synthesize num;
#synthesize date;
//bunch of other uninteresting code
- (NSDictionary*)toDictionary {
NSLog(#"=> self.num : %#", self.num);
NSDictionary *dic = #{
#"date" :self.date,
#"name" :self.name,
#"num" :self.num
};
NSLog(#"=> dic.num : %#", dic[#"num"]);
NSLog(#"=> dic : %#", dic);
return dic;
}
This is the output:
2016-05-25 21:03:44.333 FoodTruckApp[1320:614394] => self.num : 23–187
2016-05-25 21:03:44.334 FoodTruckApp[1320:614394] => dic.num : 23–187
2016-05-25 21:03:44.335 FoodTruckApp[1320:614394] => dic : {
date = "2016-05-25 21:03:44";
name = "Alameda dos Carvalhos";
num = "23\U2013187";
}
Any thought on what I might be missing here?
Cheers.
I have the following Mantle object & want to convert the dictionary to Mantle object. but the conversion always returns empty MTLModel object.
Any ideas?
//ABC.h
#interface ABC : MTLModel<MTLJSONSerializing>
#property (nonatomic, strong) NSString *Identifier;
#property (nonatomic, strong) NSString *Name;
#property (nonatomic, strong) NSString *ImageURLString;
#property (nonatomic, strong) NSString *Desc;
#property (nonatomic, strong) NSString *lastUpdated;
#end
// ABC.m
#implementation ABC
+ (NSDictionary *)JSONKeyPathsByPropertyKey {
return #{
#"Identifier" : #"id",
#"Name" : #"name",
#"Desc" : #"desc",
#"ImageURLString" : #"image_url",
#"lastUpdated" : #"last_updated_at"
};
}
#end
Calling code:
ABC *abc = [MTLJSONAdapter modelOfClass:ABC.class fromJSONDictionary:tempDict error:NULL];
The JSON dictionary is:
{
desc = "asdadasdakjqewqwmsdnasdaksdasd";
id = adsasdasdasdasd;
"image_url" = "http://upload.wikimedia.org/wikipedia/commons/thumb/1/19/abc.JPG";
"last_updated_at" = "2015-07-25 04:22:39.851710";
name = asdasdqwe;
}
The result ABC object has no contents. Can't figure what I am missing here.
Any ideas???
Try with this snippet and debug the adapterError. May have relevant information about the conversion from NSDictionary to Mantle object
//Create Mantle object from NSDictionary using MTLJSONSerialization
NSError *adapterError;
MTLModel *user = [MTLJSONAdapter modelOfClass:MTLModel.class fromJSONDictionary:dictionary error:&adapterError];
if(adapterError) {
PrintError(adapterError)
return nil;
}
id = adsasdasdasdasd;
needs to be
id = "adsasdasdasdasd";
I have this json object that I'm trying to map:
{
totalresults: 1,
results: [
{
sources: [
"The Blog",
"The website",
],
description: "Some description."",
subjects: [
"Education"
],
imageurl: "image.jpg",
authorid: 44303,
istail: false,
tailcount: 0,
displayname: "Name of me"
}
]
}
I've created a SearchPerPage object:
#interface RestSearchPerPage : NSObject
#property (strong, nonatomic) NSNumber *totalResults;
#property (strong, nonatomic) NSArray *results;
#end
I've created a SearchResults object:
#interface SearchResults : NSObject
#property (strong, nonatomic) NSArray *sources;
#property (strong, nonatomic) NSArray *subjects;
#property (strong, nonatomic) NSString *content;
#property (strong, nonatomic) NSString *imageUrl;
#property (strong, nonatomic) NSString *authorId;
#property (strong, nonatomic) NSString *displayName;
#property (strong, nonatomic) NSNumber *isTail;
#property (strong, nonatomic) NSNumber *tailCount;
#end
I'm mapping the objects just fine, but when I'm trying to map the NSArray *sources and NSArray *subjects I always get NULL.
This is my last mapping attempt on sources:
RKObjectMapping *searchResultsMapping = [RKObjectMapping mappingForClass:[SearchResults class]];
[searchResultsMapping addAttributeMappingsFromDictionary:#{ #"sources" : #"sources",
#"subjects" : #"subjects",
#"description" : #"content",
#"imageurl" : #"imageUrl",
#"authorid" : #"authorId",
#"displayname" : #"displayName",
#"istail" : #"isTail",
#"tailcount" : #"tailCount" }];
RKObjectMapping *searchPerPageMapping = [RKObjectMapping mappingForClass:[SearchPerPage class]];
[searchPerPageMapping addAttributeMappingsFromDictionary:#{ #"totalresults" : #"totalResults" }];
[searchPerPageMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"results" toKeyPath:#"results" withMapping:searchResultsMapping]];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:searchPerPageMapping
method:self.method
pathPattern:kGetSearchPerPage
keyPath:nil
statusCodes:self.statusCode]];
Please help me because I'm lost, just don't know what to do next - have no answer to this problem. Thanks in advance.
So, the problem was that I didn't mapped the array of 'results' like that:
[searchPerPageMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"results" toKeyPath:#"results" withMapping:searchResultsMapping]];
I've edited my question and fixed it.
Are you making sure that you're initializing the arrays e.g.
NSArray *subjects = [NSArray array];
It's very common to forget this :)
I have a simple JSON like this:
{
description = "Skill description",
languages = [
{
name = iOS,
skillLevel = 6
},
{
name = Android,
skillLevel = 4
}
]
}
and I need to create a model using JSON Model.
My model looks like this:
SkillModel.h
#import <Foundation/Foundation.h>
#import <JSONModel/JSONModel.h>
#protocol LanguageModel
#end
#interface SkillModel : JSONModel
// ----------------------------------------------------------------------------
//
// SkillModel
//
//
#property (strong, nonatomic) NSString *description;
//
#property (strong, nonatomic) NSArray<LanguageModel> *languages;
#end
// ----------------------------------------------------------------------------
//
// LanguageModel
//
#interface LanguageModel : JSONModel
//
#property (strong, nonatomic) NSString *name;
//
#property (strong, nonatomic) NSString *skillLevel;
#end
And the other code looks like this:
NSError *error;
NSDictionary *mobileSkillsDic = ...Dict data from json file....;
SkillModel *skillModel = [[SkillModel alloc] initWithDictionary:mobileSkillsDict error:&error];
What I'm doing wrong? I'm getting this error:
Terminating app due to uncaught exception 'Bad property protocol declaration, reason: LanguageModel is not allowed JSONModel property protocol, and not a JSONModel class.
I've got the following JSON coming from my webservice:
"GasPrices":{
"Ai92":{
"Price":30.1000,
"LastDate":"\/Date(1385337600000)\/",
"Votes":0
},
"Ai95":{
"Price":33.2000,
"LastDate":"\/Date(1385337600000)\/",
"Votes":0
}
I want to map it to NSDictionary, whose keys would be NSStrings and values would be of my custom class, say, PriceInfo.
What I got now with default setup is NSDictionary whose values are also NSDictionaries.
How can I achieve the desired mapping?
UPD. Here's my full setup for now.
#interface FillingStation : NSObject
#property (nonatomic, strong) NSNumber *uid;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSDictionary *fuelPrices;
#end
#interface PriceInfo : NSObject
#property (nonatomic, strong) NSNumber *price;
#property (nonatomic, strong) NSDate *lastDate;
#property (nonatomic, strong) NSNumber *votes;
#end
Configuring the mapping:
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[FillingStation class]];
[mapping addAttributeMappingsFromDictionary:#{
#"Id" : #"uid",
#"Title" : #"title",
#"GasPrices" : #"fuelPrices"
}];
This results in fuelPrices is NSDictionary with the structure:
NSString -> NSDictionary,
NSString -> NSDictionary,
...
And I want it to be:
NSString -> PriceInfo,
NSString -> PriceInfo,
...
And I don't want an intermediate dictionary in FillingStation which I can then manually map.
Okay, seems like I found the answer. Not exactly what I wanted, yet acceptable for me: https://github.com/RestKit/RestKit/wiki/Object-Mapping#handling-dynamic-nesting-attributes
I had to add another property to PriceInfo class and change fuelPrices from NSDictionary to NSSet (NSArray would also work, but I don't need ordering), so it became:
#interface FillingStation : NSObject
#property (nonatomic, strong) NSNumber *uid;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSSet *fuelPrices;
#end
#interface PriceInfo : NSObject
#property (nonatomic, strong) NSString *fuelType;
#property (nonatomic, strong) NSNumber *price;
#property (nonatomic, strong) NSDate *updateDate;
#property (nonatomic, assign) NSUInteger votes;
#end
and my mapping now looks like this:
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[FillingStation class]];
[mapping addAttributeMappingsFromDictionary:#{
#"Id" : #"uid",
#"Title" : #"title"
}];
RKObjectMapping *priceInfoMapping = [RKObjectMapping mappingForClass:[PriceInfo class]];
[priceInfoMapping setForceCollectionMapping:YES];
[priceInfoMapping addAttributeMappingFromKeyOfRepresentationToAttribute:#"fuelType"];
[priceInfoMapping addAttributeMappingsFromDictionary:#{
#"(fuelType).Price": #"price",
#"(fuelType).LastDate": #"updateDate",
#"(fuelType).Votes": #"votes"
}];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"GasPrices"
toKeyPath:#"fuelPrices"
withMapping:priceInfoMapping]];
Jastor May be what you're looking for. Nested objects directly mapped to known classes.