Restkit mapping complex nested array - ios

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?

Related

Posting an array of objects not working with Restkit [duplicate]

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

RestKit 0.22 : how to map only firstObject of an array?

I am receiving more data than needed: I only want to map first object of an array of objects.
Using RestKit 0.22, how to map the following Json:
{ "name": "foobar",
"tags": ["tag1", "tag2", "tag3"] }
With the following model:
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *firstTag;
To map name, I have this code:
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:#"MyObjectModel" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
[mapping addAttributeMappingsFromDictionary:#{#"name": #"name"}];
To map firstObject of tags to firstTag, I do not know how to proceed. Note: MyObjectModel is an NSManagedObject, so firstTag is #dynamic.
The tried and tested approach is to create a method on the managed object which takes the full array. That method extracts the first item and saves it to the actual NSString property. Then your mapping is as standard as all of the data types match.

storing a composite pattern (tree) in CoreData with Restkit

I have create an composite object (tree structure) in visual studio and stored in an sql server database with.
here are the screenshots:
now I want to create this model schema in core data and store the received data with RestKi.
here what I have designed with Xcode:
could someone help me to store this data with RestKit which I get in json ?
//Initialize managed object store
.
.
.
//Complete Core Data stack initialization
.
.
.
RKEntityMapping *menuMapping = [RKEntityMapping mappingForEntityForName:#"Menu" inManagedObjectStore:managedObjectStore];
menuMapping.identificationAttributes = #[#"menuComponentID"];
[menuMapping addAttributeMappingsFromDictionary:#{
#"ID":#"menuComponentID",
#"Name":#"name",
#"Description":#"descriptions",
#"Thumbnail":#"thumbnail",
#"Image": #"image",
}];
RKEntityMapping *menuItemMapping = [RKEntityMapping mappingForEntityForName:#"MenuItem" inManagedObjectStore:managedObjectStore];
[menuItemMapping addAttributeMappingsFromDictionary:#{
#"ID" : #"menuComponentID",
#"Description" : #"descriptions",
#"Name" : #"name",
#"Thumbnail":#"thumbnail",
#"Image":#"image",
#"Calorie":#"calorie",
#"Vegeterian":#"vegeterian",
}];
RKRelationshipMapping *menuRelationShip = [RKRelationshipMapping relationshipMappingFromKeyPath:#"MenuComponents" toKeyPath:#"children" withMapping:menuMapping];
[menuMapping addPropertyMapping:menuRelationShip];
RKResponseDescriptor *menuResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:menuMapping
method:RKRequestMethodGET
pathPattern:#"/api/menu/"
keyPath:nil
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objectManager addResponseDescriptor:menuResponseDescriptor];
managed objects:
menuComponnet.h
#class MenuComponent;
#interface MenuComponent : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * descriptions;
#property (nonatomic, retain) NSString * image;
#property (nonatomic, retain) NSString * thumbnail;
#property (nonatomic, retain) NSString * menuComponentID;
#property (nonatomic, retain) MenuComponent *parent;
#end
////
menu.h
#class MenuComponent;
#interface Menu : MenuComponent
#property (nonatomic, retain) NSSet *children;
#end
#interface Menu (CoreDataGeneratedAccessors)
- (void)addChildrenObject:(MenuComponent *)value;
- (void)removeChildrenObject:(MenuComponent *)value;
- (void)addChildren:(NSSet *)values;
- (void)removeChildren:(NSSet *)values;
#end
menuItem.h
#interface MenuItem : MenuComponent
#property (nonatomic, retain) NSNumber * price;
#property (nonatomic, retain) NSNumber * calorie;
#property (nonatomic, retain) NSNumber * vegeterian;
#end
when I browse the created sqlite data base. I see there is only one created table name menuComponent which has all attributes of all menu and and menuItem. while nhibernate bas created for me three table as you see in the above picture.
and parent field for all of the records is null!!
how can I successfully store this data? please explain. I'm new to RestKit.
Default JSON I got:
[{"ID":"213028b8-9f59-4d7f-bae9-a2c301815a43","MenuComponents":[{"ID":"d1a861d3-d9e8-41a4-9577-a2c301815a44","MenuComponents":[{"ID":"fa6d172d-ab26-4782-8306-a2c301815a44","Vegetarian":false,"Calorie":0,"Name":"Double Chocolate Cake","Description":"With a melted heart of chocolate","Parent":{"ID":"d1a861d3-d9e8-41a4-9577-a2c301815a44"},"Version":"AAAAAAAAF64="},{"ID":"f9050f6b-8419-4457-9ebd-a2c301815a44","Vegetarian":false,"Calorie":0,"Name":"Tiramisu","Description":"Lady finger cookies are soaked in coffee liqueur and rum","Parent":{"ID":"d1a861d3-d9e8-41a4-9577-a2c301815a44"},"Version":"AAAAAAAAF60="}],"Name":"Dessets Menu","Description":"Desserts for serving after meal","Parent":{"ID":"213028b8-9f59-4d7f-bae9-a2c301815a43"},"Version":"AAAAAAAAF6o="},{"ID":"1f50565a-eeb2-4ab0-ba7b-a2c301815a44","MenuComponents":[{"ID":"0352c5a2-081a-496d-86aa-a2c301815a44","Vegetarian":true,"Calorie":0,"Name":"Grilled Chicken Salad","Description":"Sliced, grilled chicken tops a fresh salad mix, peas","Parent":{"ID":"1f50565a-eeb2-4ab0-ba7b-a2c301815a44"},"Version":"AAAAAAAAF6w="},{"ID":"4fad8aa0-285f-4419-b85e-a2c301815a44","Vegetarian":true,"Calorie":0,"Name":"Carolina Chicken Salad","Description":"Salad mix, fried chicken tenders, peas, cheddar cheese","Parent":{"ID":"1f50565a-eeb2-4ab0-ba7b-a2c301815a44"},"Version":"AAAAAAAAF6s="}],"Name":"Salad & Combinations","Description":"Salad & Combinations","Parent":{"ID":"213028b8-9f59-4d7f-bae9-a2c301815a43"},"Version":"AAAAAAAAF6k="}],"Name":"Lunch Menu","Description":"Lunch Super Menu","Version":"AAAAAAAAF6E="},{"ID":"fa6d172d-ab26-4782-8306-a2c301815a44"},{"ID":"0352c5a2-081a-496d-86aa-a2c301815a44"},{"ID":"d1a861d3-d9e8-41a4-9577-a2c301815a44"},{"ID":"f9050f6b-8419-4457-9ebd-a2c301815a44"},{"ID":"4fad8aa0-285f-4419-b85e-a2c301815a44"},{"ID":"1f50565a-eeb2-4ab0-ba7b-a2c301815a44"}]
you can view the json here:
http://jsonviewer.stack.hu/
UPDATE:
here is menuComponent RelationShip
RKRelationshipMapping *menuComponentRelationShip = [RKRelationshipMapping relationshipMappingFromKeyPath:#"MenuComponents" toKeyPath:#"children" withMapping:menuComponentMapping];
[menuComponentMapping addPropertyMapping:menuComponentRelationShip];
but I must map menuItem too because some property are exclusively for menuItem.
RKEntityMapping *menuItemMapping = [RKEntityMapping mappingForEntityForName:#"MenuItem" inManagedObjectStore:managedObjectStore];
[menuItemMapping addAttributeMappingsFromDictionary:#{
#"ID" : #"menuComponentID",
#"Description" : #"descriptions",
#"Name" : #"name",
#"Thumbnail":#"thumbnail",
#"Image":#"image",
#"Prcie":#"price",
#"Calorie":#"calorie",
#"Vegeterian":#"vegeterian",
}];
RKResponseDescriptor *menuItemresponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:menuItemMapping
method:RKRequestMethodGET
pathPattern:#"/api/menu/"
keyPath:nil
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objectManager addResponseDescriptor:menuItemresponseDescriptor];
but after adding this responseDescriptor to mobjetManager only addes one super menu!!
How can I map menuItem and add them to database too?
Your issue doesn't seem to be related to RestKit at all, rather it is misunderstandings about Core Data.
Your children relationship should be on menu component and the inverse of the parent relationship. This allows Core Data to manage the relationships correctly (and as you expect).
You should only have 1 table in the SQLite DB file because you are using entity inheritance (it isn't a problem, just an implementation detail).
So just change the relationship in the model and you should be good to go.

Parsing JSON using RestKit

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.

Relationships not Connected with Core Data and RestKit

I've been working with RestKit (0.9.3) to populate some Core Data in my app. The entity objects are created correctly, but the relationships between them are not created. From what I can tell, I have things setup correctly according to:
https://github.com/RestKit/RestKit/wiki/Object-mapping
RKRelationshipMappingExample in the Examples folder
So, here's a sample of the JSON that I'm getting back from the server:
{
"artist" : {
"artistId" : 123,
"artistName" : "The Artist",
"albums" : [
{
"albumPrice" : 12.99,
"albumId" : 456,
"trackCount" : 12,
"albumName" : "Album Title",
},
{
"albumPrice" : 10.99,
"albumId" : 789,
"trackCount" : 10,
"albumName" : "Another Album Title",
}
]
}
}
And I am using RestKit to populate the following two managed objects:
#interface Artist : NSManagedObject
#property (nonatomic, retain) NSNumber * artistId;
#property (nonatomic, retain) NSString * artistName;
#property (nonatomic, retain) NSSet *albums;
#end
#interface Artist (CoreDataGeneratedAccessors)
- (void)addAlbumsObject:(Album *)value;
- (void)removeAlbumsObject:(Album *)value;
- (void)addAlbums:(NSSet *)values;
- (void)removeAlbums:(NSSet *)values;
#end
#interface Album : NSManagedObject
#property (nonatomic, retain) NSNumber * albumId;
#property (nonatomic, retain) NSString * albumName;
#property (nonatomic, retain) NSNumber * albumPrice;
#property (nonatomic, retain) NSNumber * trackCount;
#property (nonatomic, retain) NSManagedObject *artist;
#end
I've setup the following configurations with RestKit, and the intent is for 3 Core Data items to be created: one artist and two albums. The artist entity has a "albums" relationship which should be a set of these two albums.
// Initialize our RestKit singleton
RKClient *client = [RKClient clientWithBaseURL:API_URL];
// Initialize for Object mapping
RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:API_URL];
objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:#"AppName.sqlite"];
// Configure ALBUM mapping
RKManagedObjectMapping* albumMapping = [RKManagedObjectMapping mappingForClass:[Album class]];
albumMapping.primaryKeyAttribute = #"albumId";
[albumMapping mapKeyPath:#"albumId" toAttribute:#"albumId"];
[albumMapping mapKeyPath:#"albumName" toAttribute:#"albumName"];
[albumMapping mapKeyPath:#"albumPrice" toAttribute:#"albumPrice"];
[albumMapping mapKeyPath:#"trackCount" toAttribute:#"trackCount"];
// Configure ARTIST mapping
RKManagedObjectMapping* artistMapping = [RKManagedObjectMapping mappingForClass:[Artist class]];
artistMapping.primaryKeyAttribute = #"artistId";
[artistMapping mapKeyPath:#"artistId" toAttribute:#"artistId"];
[artistMapping mapKeyPath:#"artistName" toAttribute:#"artistName"];
[artistMapping mapKeyPath:#"albums" toRelationship:#"albums" withMapping:albumMapping];
// Register mappings with the provider
[[RKObjectManager sharedManager].mappingProvider setMapping:albumMapping forKeyPath:#"albums"];
[[RKObjectManager sharedManager].mappingProvider setMapping:artistMapping forKeyPath:#"artist"];
And then later in my program, I load the data:
RKObjectManager *objectManager = [RKObjectManager sharedManager];
[objectManager loadObjectsAtResourcePath:#"/artist/123/albums" delegate:self];
After this is executed, my Core Data store is populated with the three objects (one artist and two albums), but the relationship between them is not created.
The result is that I can fetch this list of albums directly, or I can fetch the artist directly. But if I try to use: artist.albums the result is empty.
Can anyone offer suggestions on what I could be doing wrong, or how to further troubleshoot this?
Thanks so much.
EDIT: Update 10/26
I just setup a small sample project with these same configurations and everything was loaded correctly (i.e. The artist entity was created with a relationship to it's albums). Sadly, this means that the issue is something in my larger project, rather than in what I outlined here earlier. With that said, I'll continue trudging though and updating, so if anyone has advice on how to troubleshoot this or where in particular to look, I would greatly appreciate it.
EDIT: Resolved
Embarrassingly, the problem was simply that I was using the wrong base url. I'll post full details (in case it can help anyone else) tomorrow.
Well... we have a resolution. I'm embarrassed to say that the problem was simply that I was using the wrong base url in my main project. I made some updates to the JSON returned by the local copy of the API, but the base url was still pointing to the copy of the API online.
The change I made was to format the JSON this way rather than having "artist" and "albums" be separate entities in the JSON.

Resources