I have been using RestKit for sometime but some APIs have changed in the latest version and I'm no longer able to parse simple JSON.
Here's the payload I have:
{
"result":true,
"items":[
{
"id":"1",
"receiver":"11011101"
},
{
"id":"2",
"receiver":"11011101"
}
]
}
How can I parse the contents of the "items" dictionary as instances of the object Conversation I have created?
Using the code below doesn't work (objects are never mapped):
RKObjectMapping* conversationMapping = [RKObjectMapping mappingForClass:[Conversation class]];
[conversationMapping mapKeyPath:#"id" toAttribute:#"id"];
[conversationMapping mapKeyPath:#"receiver" toAttribute:#"receiver"];
[[RKObjectManager sharedManager].mappingProvider setMapping:conversationMapping forKeyPath:#"items"];
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/getConversations" delegate:self];
Conversation class
#interface Conversation : NSObject {
NSString *id;
NSString *receiver; }
+ (void)objectMapping;
#property (nonatomic, strong) NSString *id; #property (nonatomic, strong) NSString *receiver;
#end
#implementation Conversation
#synthesize id;
#synthesize receiver;
+ (void)objectMapping {
RKObjectMapping* conversationMapping = [RKObjectMapping mappingForClass:[Conversation class]];
[conversationMapping mapKeyPath:#"id" toAttribute:#"id"];
[conversationMapping mapKeyPath:#"receiver" toAttribute:#"receiver"];
[[RKObjectManager sharedManager].mappingProvider setMapping:conversationMapping forKeyPath:#"items"];
}
#end
How is your root object defined (the one that holds "result" and your Conversation "items")? That should look something like this:
#interface MyResponse
#property (nonatomic, strong) NSArray* items;
#property (nonatomic, assign) BOOL result;
with the appropriate mapping for that as well.
I solved the problem. It was something totally not related to RestKit. The content type of the response coming back from the server was not set to JSON, after fixing that object mapping worked fine.
Related
This question already has an answer here:
Restkit request not sending parameters
(1 answer)
Closed 8 years ago.
I have the following two entities
#interface MEContactInfo : NSObject
#property (nonatomic,strong) NSString* phone ;
#property (nonatomic,strong) NSString* email;
#end
#interface MEContact : NSObject
#property (nonatomic,strong) NSString* _id ;
#property (nonatomic,strong) NSString* lastName;
#property (nonatomic,strong) NSString* firstName;
#property (nonatomic,strong) NSString* data ;
#property (nonatomic,strong) NSMutableArray* contactInfos ;
#end
The second entity contact contains the array of contact infos. Now I want to post this to my server but I am not able to do so. My mappings are as following:
RKObjectMapping* contactMapping = [RKObjectMapping mappingForClass:[MEContact class]];
[contactMapping addAttributeMappingsFromArray:#[#"_id",#"lastName",#"firstName",#"data"]];
RKObjectMapping* contactInfosMapping = [RKObjectMapping mappingForClass:[MEContactInfo class]];
[contactInfosMapping addAttributeMappingsFromArray:#[#"email",#"phone"]];
[contactMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"contactInfos" toKeyPath:#"contactInfos" withMapping:contactInfosMapping]];
My request descriptor is as following:
requestDescriptor = [RKRequestDescriptor
requestDescriptorWithMapping:[contactMapping inverseMapping]
objectClass: [MEContact class]
rootKeyPath:nil method:RKRequestMethodAny];
Now when I post something like this:
{ firstName:”abc”,
lastName:”xyz”,
contactInfos: [{
email:”test#test.com”,
phone:”9999999999”
}]
}
I receive
{
firstName:”abc”,
lastName:”xyz”,
contactInfos: [ ”test#test.com”,”9999999999”]
}
If I have multiple entries in the contactInfos array, they all are appended to the contactInfos array I receive on the server side. Basically the contactInfo object is flattening in an array. Can you please let me know how I can fix this.
I got it to work. Everything above was correct. The problem was that data was not going as JSON to the server. The solution was that I had to set request serialization MimeType which can be done by doing this
[objectManger setRequestSerializationMIMEType:RKMIMETypeJSON];
Thanks
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.
I've been trying to map the following object from the JSON response and from everything I see in the console output, there isn't any reason why the mapping isn't successful - I appreciate if anyone could have a check and see:
#interface RKElectionsModel : NSObject
#property (nonatomic, assign) bool isActive;
#property (nonatomic, strong) NSNumber *electionID;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *summary;
#property (nonatomic, strong) NSNumber *availableSeats;
#property (nonatomic, strong) NSNumber *candidatesCount;
#property (nonatomic, strong) NSNumber *withdrawnCount;
#property (nonatomic, strong) NSSet *candidates;
#end
/**
* Election Detail Mapping: Getting all election details, we have some extra information from
* the API call
*
*/
RKObjectMapping *electionDetailsMapping = [RKObjectMapping mappingForClass:[RKElectionsModel class]];
// Map JSON -> entities
[electionDetailsMapping addAttributeMappingsFromDictionary:#{
#"id": #"electionID",
#"title": #"title",
#"summary": #"summary",
#"active": #"isActive",
#"availableSeats": #"availableSeats",
#"candidatesCount": #"candidatesCount",
#"withdrawnCount": #"withdrawnCount"
}];
// Register our mappings with the provider
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:electionDetailsMapping pathPattern:#"/api/elections/:electionID/all" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
Console output on pastebin and any examples of the JSON response you can visit here
Appreciate any help,
Lewis
Seems like your trying to map a NSString to NSNumber.
In your NSObject try to add the following validation and transform the string you receive from the server to a NSNumber when the mapping starts.
- (BOOL)validateAvailableSeats:(id *)ioValue error:(NSError **)outError {
// Force the value to be a NSNumber
*ioValue = [NSNumber numberWithDouble:[(NSString*)value doubleValue] ]
return YES;
}
In the RestKit Wiki you'll find more transformations for your values.
I am trying to use restkit to read/parse an xml feed. which contains a nested array of artists. I can map other relationships but am unclear what I am to do with the artist relationship below.
My dataset looks like:
<JamBase_Data>
<Results_Title>Jersey City, NJ</Results_Title>
<event>
<event_id>1896611</event_id>
<artists>
<artist>
<artist_id>96929</artist_id>
<artist_name>The Happy Problem</artist_name>
</artist>
<artist>
<artist_id>29817</artist_id>
<artist_name>Craig Greenberg</artist_name>
</artist>
</artists>
<event_date>1/9/2013</event_date>
<venue>
<venue_id>48553</venue_id>
<venue_name>The Cake Shop</venue_name>
<venue_city>New York</venue_city>
<venue_state>NY</venue_state>
<venue_zip>10002</venue_zip>
</venue>
<event_url>
http://www.jambase.com/Shows/Event.aspx?eventID=1896611
</event_url>
</event>
</JamBase_Data>
Mappings:
RKObjectMapping *eventMapping = [RKObjectMapping mappingForClass:[Event class]];
RKObjectMapping *artistMapping = [RKObjectMapping mappingForClass:[Artist class]];
RKObjectMapping *venueMapping = [RKObjectMapping mappingForClass:[Venue class]];
[artistMapping mapKeyPathsToAttributes: #"artist_name",#"artist_name", nil];
[venueMapping mapKeyPathsToAttributes: #"venue_city",#"venue_city",#"venue_state",#"venue_state", #"venue_name", #"venue_name", nil];
[objectManager.mappingProvider setMapping:eventMapping forKeyPath:#"JamBase_Data.event"];
[eventMapping mapKeyPath:#"artists" toRelationship:#"artists" withMapping:artistMapping];
[eventMapping mapKeyPath:#"venue" toRelationship:#"venue" withMapping:venueMapping];
Venue.h
#interface Event : NSObject
#property (nonatomic, strong) NSSet *artists;
#property (strong, nonatomic) Venue *venue;
#end
Artist.h
#interface Artist : NSObject
#property (nonatomic, strong) NSNumber *artist_id;
#property (nonatomic, strong) NSNumber *artist_name;
I can get venue to map correctly, but cannot figure out how to get Artists to map. Is there something i need to do to tell the object manager to make an coming off of the event?
Any help would be greatly appreciated as this is my first foray into iOS development.
The Artists object you see in the XML translates to an NSArray. Now that contains objects of type Artists. Have you thought about it that way?
I working with it for two days... I want get remote xml then parse/map it to core data. I have read bunch of tutorials, so at this moment I can connect with local server (yyuupii!), get xml, but I have problem with mapping. I get
-[RKObjectLoader canParseMIMEType:] Unable to find parser for MIME Type 'application/xml'
-[RKObjectLoader isResponseMappable] Encountered unexpected response with status code: 200 (MIME Type: application/xml -> URL:
http:///list.xml -- http:/// --
http:/// -- http:///) 2012-10-24
14:13:12.201 Sierpien[4650:907] Error
Domain=org.restkit.RestKit.ErrorDomain Code=4 "The operation couldn’t
be completed. (org.restkit.RestKit.ErrorDomain error 4.)"
Could you gave me some advice I will be thankful.
My XML
<packs>
<pack>
<cover>cover.png</cover>
<info>Jakis.adres.pl</info>
<link>Opis</link>
<name>wrzesień</name>
<price>5.00</price>
</pack>
<pack>
<cover>cover2.png</cover>
<info>Jakis1.adres.pl</info>
<link>Opis31</link>
<name>wrzesień12</name>
<price>15.00</price>
</pack>
</packs>
My Entity
#interface Pack : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * link;
#property (nonatomic, retain) NSString * price;
#property (nonatomic, retain) NSString * info;
#property (nonatomic, retain) NSString * cover;
#end
My Implementation
- (id)initClient
{
self = [super init];
if (self) {
RKObjectManager *client = [RKObjectManager objectManagerWithBaseURL:[RKURL URLWithString:#"http://10.1.1.5:8888/"]];
NSLog(#"I am your RKObjectManager singleton : %#", [RKObjectManager sharedManager]);
client.serializationMIMEType = RKMIMETypeXML;
RKObjectMapping* listMapping = [RKObjectMapping mappingForClass:[Pack class]];
[listMapping mapKeyPath:#"cover" toAttribute:#"cover"];
[listMapping mapKeyPath:#"name" toAttribute:#"name"];
[listMapping mapKeyPath:#"info" toAttribute:#"info"];
[listMapping mapKeyPath:#"link" toAttribute:#"link"];
[listMapping mapKeyPath:#"price" toAttribute:#"price"];
[[RKObjectManager sharedManager].mappingProvider setMapping:listMapping forKeyPath:#"packs.pack"];
}
return self;
}
- (void)loadPacks {
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/list.xml" delegate:self];
}
Ok I throw away RKObjectManager, now I connect with RKClient, get xml with
[[RKClient sharedClient] get:#"/list.xml" delegate:self];
Then I parse Xml by GDataXML, fill Pack with that parsed data. It works.