I'm having an issue with ResKit for managing orphaned objects when, the JSON received from the same webService, must be mapped in multiple entities.
I've followed the example here http://restkit.org/api/latest/Classes/RKManagedObjectRequestOperation.html (under section "Deleting orphaned objects") and I can get orphaned objects deleted, but only for a single entity.
Let's see some code...
What follow is a (small part) JSON that I receive from webService.
{
"families": [
{
"id": "000",
"desc": "desc_1"
},
{
"id": "001",
"desc": "desc_2"
}
],
"categories": [
{
"id": "00000000",
"desc": "test"
....//others attributes
},
{
"id": "00000001",
"desc": "test"
....//others attributes
}
]
}
I'm mapping this JSON correctly to 2 different entities: Category and Family.
Now, for what I've understand, I can delete orphaned objects (objects no more received from server) by adding a FetchRequestBlock to my RKObjectManager.
Here is how I define it:
[objectManager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) {
RKPathMatcher* pathMatcher = [RKPathMatcher pathMatcherWithPattern:#"getData.asp"];
NSDictionary *dic = nil;
if ([pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:YES parsedArguments:&dic]) {
NSFetchRequest *fetchRequest = [NSFetchRequest new];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Family" inManagedObjectContext: managedObjectStore.mainQueueManagedObjectContext];
fetchRequest.entity = entity;
return fetchRequest;
} else
return nil;
}];
My questions: as you can see, in the FetchRequestBlock, I'm defining only the entity "Family", but I want to delete orphaned objects of "Category" entity inside the same block...is this possible ? Or I have to create another similar block that differs only for the entity name ?
And is there a method to add a "keyPath" (like "categories" or "families" in this example) to the FetchRequestBlock so I can be sure to delete the correct NSManagedObject? Or is this unnecessary?
EDIT:
For completion I add some more code, so I think you can understand better what I'm doing (and, in case, correct me if I'm doing something wrong...)
Here is how I define RKResponseDescriptor, where I can correctly associate it to a "KeyPath":
//Categories
RKResponseDescriptor *categoriesDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:categoriesMapping
method:RKRequestMethodGET
pathPattern:#"getData.asp" keyPath:#"categories"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
//Families
RKResponseDescriptor *familiesDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:familiesMapping
method:RKRequestMethodGET
pathPattern:#"getData.asp" keyPath:#"families"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
And I retrieve data from webService using the following code:
[[RKObjectManager sharedManager] getObjectsAtPath:#"getData.asp" parameters:#{kAuthKeyName : kAuthKeyValue} success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
//Success block
//Before entering in this block, I can see with debug that ResKit try to
//automatically delete objects that return from the "FetchRequestBlock" defined in above code...
}failure:^(RKObjectRequestOperation *operation, NSError *error) {
//Failure Block
}];
Related
how to i set response mapping to manager with path pattern ..if the getobjects at path is different from path pattern that is used to map the response.
[manager addResponseDescriptorsFromArray:
#[[RKResponseDescriptor responseDescriptorWithMapping:categoryMapping
pathPattern:A
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]]];
[manager getObjectsAtPath:A/ID
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#" Category success");
[self.delegate didReceiveAssignedCategories];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Category failure");
}];
response mapping path ie:A must be set to dynamic path used to getobject ie:A/ID .
ex:
Call 1)
A = /getAllCategories
A/ID = /getAllCategories/123
call 2)
A = /getAllCategories
A/ID = /getAllCategories/456
response mapping is same for 123, 456
only while getting the objects i am using different urls ie: with id's attached.
how to do that ?
If you have 2 path patters which both return the same type of data then you can use the same mapping with 2 different response descriptors.
If you have 1 path pattern which can return 2 different types of data then you need to use RKDynamicMapping to 'intercept' the incoming data and decide which mapping is actually required.
From your edited question, 'pattern' is the important thing that you have misunderstood. You need to use a path pattern, not a static path:
#"getAllCategories/:identity"
1) First create response mapping like
[manager addResponseDescriptorsFromArray:
#[[RKResponseDescriptor responseDescriptorWithMapping:categoryMapping
pathPattern:#"getAllCategories/:categoryID"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]]];
2)Create Class with categoryID in it.
[CategoryRequest class]
3) create object of that class and set categoryID
CategoryRequest *categoryRequest = [CategoryRequest alloc] init];
categoryRequest.categoryID = #"123";
4)call getobject using that object
[manager getObject:categoryRequest
path:#"getAllCategories/123"
parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
if another call is required to be made for same mapping create object of of category request class set new category id and call get object using that categoryresquest and required path patter.
Hello friends in stackoverflow:
I am having problem mapping data from the api using restkit.I really want to know where my mistake is.
Json format:
{
data: {
-current_condition: [1]
0: {
cloudcover: "16"
humidity: "59"
- weatherDesc: [1]
0: {
value: "Clear"
}
- weather: [5]
0: {
tempMinC: "10"
tempMinF: "50"
weatherCode: "119"
- weatherDesc: [1]
0: {
value: "Cloudy"
}
.......
}
here is my code how to do the mapping (I tried to mapping the 'cloudcover,humidity',and both 'weatherDesc' in current_condition and weather)
-(void)configureRestKit{
NSURL *baseURL = [NSURL URLWithString:#"http://www.raywenderlich.com"];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
RKObjectMapping *currentMapping = [RKObjectMapping mappingForClass:[CurrentCondition class]];
[currentMapping addAttributeMappingsFromArray:#[#"cloudcover",#"humidity",#"weatherDesc"]];
[currentMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"current_condition" toKeyPath:#"current_condition" withMapping:currentMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:currentMapping method:RKRequestMethodGET pathPattern:#"/demos/weather_sample/weather.php" keyPath:#"data.current_condition" statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objectManager addResponseDescriptor:responseDescriptor];
//weahter Desc
RKObjectMapping *weatherMapping = [RKObjectMapping mappingForClass:[Weather class]];
[weatherMapping addAttributeMappingsFromDictionary:#{#"weatherDesc": #"myweatherDesc"}];
[weatherMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"weather" toKeyPath:#"weather" withMapping:weatherMapping]];
RKResponseDescriptor *weatherresponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:weatherMapping method:RKRequestMethodGET pathPattern:#"/demos/weather_sample/weather.php" keyPath:#"data.weather" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:weatherresponseDescriptor];
}
-(void)loadCurrentCondition{
NSDictionary *queryParams = #{#"format": #"json"};
[[RKObjectManager sharedManager] getObjectsAtPath:#"/demos/weather_sample/weather.php" parameters:queryParams success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
_myArr = mappingResult.array;
[self Humidity];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"The error is :%#",error);
}];
}
-(void)Humidity{
restkitCurrentCondition *rkCC = [_myArr objectAtIndex:0];
NSLog(#"///////////////////////the humidity is: %ld",rkCC.humidity.longValue);
NSLog(#"//////////////////// the cloudcover is: %ld",rkCC.cloudcover.longValue);
NSLog(#"/////////////// the weatherDesc is %#",rkCC.weatherDesc[0][#"value"]);
NSLog(#"///////// the weatherDesc in weather is %#",rkCC.restkitweather.myweatherDesc[0][#"value"]);
NSLog(#"///////// the weatherDesc in weather is %#",rkCC.restkitweather.myweatherDesc);
}
here is what I get:
2014-07-16 14:21:36.076 myRestSample[3783:60b] I restkit:RKLog.m:33 RestKit logging initialized...
2014-07-16 14:21:36.154 myRestSample[3783:60b] I
restkit.network:RKObjectRequestOperation.m:150 GET
'http://www.raywenderlich.com/demos/weather_sample/weather.php?format=json'
2014-07-16 14:21:36.289 myRestSample[3783:3a0f] I
restkit.network:RKObjectRequestOperation.m:220 GET
'http://www.raywenderlich.com/demos/weather_sample/weather.php?format=json' (200 OK / 6
objects) [request=0.1323s mapping=0.0024s total=0.1525s]
2014-07-16 14:21:36.289 myRestSample[3783:60b] -[Weather humidity]: unrecognized
selector sent to instance 0x8f8eb30
I tried to change the descritor's keypath to 'nil',looks like this
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:currentMapping
method:RKRequestMethodGET
pathPattern:#"/demos/weather_sample/weather.php" keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
The Weather and CurrentCondition are NSObject and there are four properties in CurrentCondition(cloudcover,humidity, NSArray *weaterDesc,Weather *restkitweather).There are only two properties in Weather.h (NSArray *myweatherDesc,*weatherDesc)
It seems I have already got 6 objects but why I got '[Weather humidity] Unreconized'.
Can anyone help??please..
'[Weather humidity] Unreconized'
This means that you have a Weather Instance, but you are treating it as a current conditions instance.
As per my answer to your other question you should not be using _myArr = mappingResult.array; because you can't be sure what the array contains. Instead you should be using the dictionary and extracting the correct type of object for your needs based on the key path.
I have two EndPoints:
http://rest.domain.com/invite
http://rest.domain.com/template
Depending on what options the User selects, I need to able to PUT, POST, & Delete on both EndPoints.
Mapping for all three methods is slightly different. Mapping for each EndPoint is also different.
What's the best way to setup mappings so they are loaded once and can be used multiple times for each EndPoint depending upon what option (PUT, POST, or Delete) the User selects? I have to accomplish this on one storyboard Scene!
Currently, below is the code that I use when POSTing to the /invite EndPoint (it crashes after the first POST b/c I'm remapping):
- (void)sendInvite:(NSInteger)methodType
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.objectManager = [self getObjectManager];
self.objectManager.managedObjectStore = appDelegate.managedObjectStore;
RKEntityMapping *invitationMapping = [RKEntityMapping mappingForEntityForName:kInvite
inManagedObjectStore:self.objectManager.managedObjectStore];
RKEntityMapping *activityMapping = [RKEntityMapping mappingForEntityForName:kActivity
inManagedObjectStore:self.objectManager.managedObjectStore];
Invite *invitation;
switch (methodType) {
case POST:
{
invitationMapping = [RESTMappingProvider invitionPostMapping:invitationMapping];
activityMapping = [RESTMappingProvider activityPostMapping:activityMapping];
[invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kActivitiesRelationship
toKeyPath:kActivitiesRelationship
withMapping:activityMapping]];
invitation = [self inviteForMethod:POST]; //This method just assigns values to the attributes
[self setupDescriptors:invitationMapping forKeyPath:kMeetupKeyPath descriptorClassIsTemplate:NO];
[self.objectManager.HTTPClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[self.objectManager.managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:NO];
[self.objectManager postObject:invitation path:kMeetupKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[self removeDuplicateObjects]; //After removing relationship Dups, I save to persistent store
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
}
break;
case PUTACCEPT:
case PUTDECLINE:
case PUTEDIT:
{
invitationMapping = [RESTMappingProvider invitionPutMapping:invitationMapping];
activityMapping = [RESTMappingProvider activityPutMapping:activityMapping];
[invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kActivitiesRelationship
toKeyPath:kActivitiesRelationship
withMapping:activityMapping]];
invitation = [self inviteForMethod:methodType]; //This method just assigns values to the attributes
[self setupDescriptors:invitationMapping forKeyPath:kMeetupKeyPath descriptorClassIsTemplate:NO];
[self.objectManager.HTTPClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[self.objectManager putObject:invitation path:kMeetupKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure in PUT");
}];
}
break;
}
}
I do something similar for the Templates EndPoint
- (void)saveAsTemplate
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.objectManager = [self getObjectManager];
self.objectManager.managedObjectStore = appDelegate.managedObjectStore;
RKEntityMapping *invitationMapping = [RKEntityMapping mappingForEntityForName:kInviteTemplates
inManagedObjectStore:self.objectManager.managedObjectStore];
invitationMapping = [RESTMappingProvider invitionTemplateMapping:invitationMapping];
RKEntityMapping *activityMapping = [RKEntityMapping mappingForEntityForName:kActivityTemplates
inManagedObjectStore:self.objectManager.managedObjectStore];
activityMapping = [RESTMappingProvider activityTemplateMapping:activityMapping];
[invitationMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:kTemplateActivitiesRelationship
toKeyPath:kTemplateActivitiesRelationship
withMapping:activityMapping]];
STInvitesTemplate *invitation = [self templateForInvite];//this method assigns values to the attributes
[self setupDescriptors:invitationMapping forKeyPath:kTemplatesKeyPath descriptorClassIsTemplate:YES];
[self.objectManager.HTTPClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[self.objectManager postObject:invitation path:kTemplatesKeyPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
}
Request & Response Descriptor:
- (void)setupDescriptors:(RKEntityMapping *)invitationMapping forKeyPath:(NSString *)keyPath descriptorClassIsTemplate:(BOOL)isTemplate
{
RKRequestDescriptor *requestDescriptor;
if (isTemplate)
{
requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[invitationMapping inverseMapping] objectClass:[Template class] rootKeyPath:nil method:RKRequestMethodAny];
}
else
{
requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[invitationMapping inverseMapping] objectClass:[Invite class] rootKeyPath:nil method:RKRequestMethodAny];
}
NSIndexSet *statusCodeSet = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:invitationMapping
method:RKRequestMethodGET
pathPattern:keyPath
keyPath:nil
statusCodes:statusCodeSet];
self.objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[self.objectManager addRequestDescriptor:requestDescriptor];
[self.objectManager addResponseDescriptor:responseDescriptor];
}
I know the approach above is incorrect as Xcode crashes after I POST or PUT. I haven't implemented Delete yet b/c I'm not sure how to set this up correctly.
Do I load the mappings ONCE in viewDidLoad? Do I create PUT, POST, DELETE x 2 EndPoints = 6 RKEntityMappings?
Need some guidance on best practice. Code sample or some step-by-step instructions would be great!
You need to create an many different mappings as you have different structure responses to process. If the responses for one entity type are all subsets of some common superset then you can use just one (for mapping responses and another for requests). You don't say anything about the expected JSON so I can't tell.
In your code I see 2 request descriptors and 1 response descriptor. The requests match against any method so will always be used. The response descriptor matches only GET responses so won't work for anything. You should likely have one response descriptor per end point per method (as you say they need different mappings to be applied to each).
viewDidLoad isn't necessarily the correct place to configure this. It looks like you have a single object manager and this configuration code should run when it is created (not when it is used, brcause the view can be loaded multiple times and the configuration would be duplicated).
I have a request gives me two part of data, the json looks like this
{
"banner_content":
[
{
"activi_id":"1",
"activi_pic":
},
{
"activi_id":"2",
"activi_pic":
},
],
"categories":
[
{...},
{...},
]
}
When I write responseDescriptor to map the data, I have found I must define a model which contains banner_content array and categories array (I don't want to )
or else I have to write two responseDescriptors to do, when the request is done, I have to get the two parts of data from (RKMappingResult *)mappingResult
then get array like [mappingResult objectForKey:#"banner_content"] and [mappingResult objectForKey:#"categories"]
it's weird
below is my code
File:RCategory.m
#implementation RCategory
+ (NSDictionary *)_mapping {
return #{#"title" : #"title"};
}
+ (RKObjectMapping *)mapping {
// Setup our object mappings
RKObjectMapping *categoryMapping = [RKObjectMapping mappingForClass:[self class]];
[categoryMapping addAttributeMappingsFromDictionary:[[self class] _mapping]];
RKObjectMapping *itemMapping = [RCategoryItem mapping];
RKRelationshipMapping* relationShipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:#"content"
toKeyPath:#"items"
withMapping:itemMapping];
[categoryMapping addPropertyMapping:relationShipMapping];
return categoryMapping;
}
#end
File:RAd.m ignored
File:viewController.m
- (void)loadCategory {
// Load the object model via RestKit
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKObjectMapping *categoryMapping = [RCategory mapping];
RKResponseDescriptor *categoryResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:categoryMapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:#"category"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectMapping *adsMapping = [RAd mapping];
RKResponseDescriptor *adResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:adsMapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:#"banner_content"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
//** DO I MUST ADD TWO RESPONSE_DESCRIPTOR FOR ONE REQUEST??**
[objectManager addResponseDescriptor:categoryResponseDescriptor];
[objectManager addResponseDescriptor:adResponseDescriptor];
[objectManager getObjectsAtPath:RPATH(CATEGORY_PATH)
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray* statuses = [mappingResult array];
[self.categories addObjectsFromArray:statuses];
if ([self isViewLoaded]) {
[self.tableView reloadData];
}
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}];
}
Does anybody have a better way to solve my problem?
BTW I write -mapping in the Model Class, It's the easiest and best way I can think out
I would like to know how do you write the mapping.
You need 2 response descriptors because the response has 2 logically separate parts. This is fine. If you were using Core Data then you wouldn't be concerned as all your objects would simply be saved to the context and you can fetch them as required. With object mapping, if you don't care about the grouping then you can get an array of all objects from the mapping result.
Creating your mappings from data returned by the model objects is fine - but it does limit you because you can only have one source key per destination key. What happens when you have a different response for the same object with a different key that means the same as some other key (hopefully you don't, but it all depends on the server API).
My JSON response looks like this:
{
"enabled": false,
"number_of_articles": 20,
"new_users": [
{
"id": "5001",
"name": "Jimmy Valner"
},
],
"articles" : [
{
"id" : 33122,
"title" : "Something",
"authors": [
{
"id": "511",
"name": "Somebody"
},
{
"id": "51",
"name": "Somebody else"
}
}]
}
Not really a proper RESTful response I know. But I have to map it somehow to two different Entities (User and Article). A already have a working code for the articles part. It maps the Article and the Articles as a relation.
I'm doing it like this:
RKMapping *mapping = [MappingProvider articlesMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor
responseDescriptorWithMapping:mapping
pathPattern:#"/articles/:userId/latest"
keyPath:#"articles"
statusCodes:statusCodeSet];
NSURLRequest *request = [[RKObjectManager sharedManager] requestWithObject:nil
method:RKRequestMethodGET
path:[NSString stringWithFormat:#"/articles/%#/latest", [[CredentialStore sharedInstance] userId]]
parameters:nil];
RKManagedObjectStore *store = [[DataModel sharedDataModel] objectStore];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request
responseDescriptors:#[responseDescriptor]];
operation.managedObjectCache = store.managedObjectCache;
operation.managedObjectContext = store.mainQueueManagedObjectContext;
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"%#", mappingResult.array);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"ERROR: %#", error);
NSLog(#"Response: %#", operation.HTTPRequestOperation.responseString);
}];
[operation start];
This is working as expected. I provide the mapping instructions in the + (RKMapping *)articlesMapping method. Even the authors part of the JSON response is mapped properly.
Now I want to map new_users array to a different entity (User obviously). How can I do that by not invoking another request to the server ? I had some success with creating another RKManagedObjectRequestOperation *operation but that of course triggers another network request to the server which I want to avoid.
Should I look for the solution here in the RKObjectManager or should I somehow change the keyPath to start at root level and the do the mapping for different entities in the + (RKMapping *) method (probably not) ?
And another question .. how can I access the enabled, number_of_articles properties from this JSON? Again, I'm not dealing with a nice structured Restful response, but I have to deal with it somehow. I only want to access this properties somehow ... no mapping to entities needed.
RKManagedObjectRequestOperation has the method initWithRequest:responseDescriptors: for a reason. Note specifically the 's' on responseDescriptors and the fact that you're passing an array. This means you can configure multiple response descriptors, each with the same path pattern but different key paths and RestKit will process each of them on the response received from the server.
Note that when you do this you probably want to change your NSLog(#"%#", mappingResult.array); because it would contain all of the top level items in the list. Instead, you should probably use NSLog(#"%#", mappingResult.dictionary);