RestKit Object Mapping - One Entity, two mappings - iphone

After my last question was solved the JSON I'm receiving from the server changed to the following and I'm stuck handling the mapping to save the data with Core Data.
Entity
Key
- alias
- key
- keyType
- keyword
- unid
- until
JSON (from Server)
{
"documents": 1026,
"configuration":
{
...
},
"data":
[
{
"alias": "",
"key": "SALUTATION",
"keyType": "S",
"keyword": "Mr",
"unid": ""
},
...
{
"alias": "Automobile",
"key": "ACCOUNT_MARKET_SEGMENT",
"keyType": "A",
"keyword": "Automobile",
"unid": ""
}
],
"documentsFound": 770,
"maxCount": -1,
"since": "20120326200001",
"until": "20120326211309"
}
Now I want to map all the data from "data" plus the key "until" for the entity "Key" but can't find the right solution. My mapping so far to get the data looks like this and works well but misses the "until"-key, of course.
RKManagedObjectMapping* keyMapping = [RKManagedObjectMapping mappingForClass:[Key class]];
keyMapping.rootKeyPath = #"data";
[keyMapping mapKeyPath:#"key" toAttribute:#"key"];
[keyMapping mapKeyPath:#"keyword" toAttribute:#"keywordEN"];
[keyMapping mapKeyPath:#"alias" toAttribute:#"alias"];
keyMapping.setDefaultValueForMissingAttributes = YES;
Thanks for your ideas!

You are probably going to want to do two mappings. The first mapping will enclose the entire object and will have a relationship to the nested 'data' path.
RKObjectMapping *keyMapping = [RKObjectMapping mappingForClass:[Key class]];
[keyMapping mapAttributes:#"alias", #"key", nil];
[keyMapping mapKeyPath:#"keyword" toAttribute:#"keywordEN"];
RKObjectMapping *outerMapping = [RKObjectMapping mappingForClass:[Container class]];
[outerMapping mapKeyPath:#"data" toRelationship:#"keys" withMapping:keyMapping];
[outerMapping mapAttributes:#"since", #"until", "maxCount", "documentsFound", nil];
That will give you a new object with your metadata and then an array of the key objects on the keys attribute of your container. Rather than using the rootKeyPath, you can use the resourcePath based mapping registration on the 0.9.4 development branch (about to be released).

Related

datatype of complextype entity is null when returning an array of complex types

We have created a complextype field "carriers" which is an array of Carrier objects. See below metadata
"dataProperties": [
{
"name": "carriers",
"complexTypeName":"Carrier#Test",
"isScalar":false
}]
The Carrier entity is defined as below:
{
"shortName": "Carrier",
"namespace": "Test",
"isComplexType": true,
"dataProperties": [
{
"name": "Testing",
"isScalar":true,
"dataType": "String"
}
]
}
We are trying to return an array of complextype in breeze from a REST service call. We get an error in breeze.debug.js in the method proto._updateTargetFromRaw. The error is because the datatype is null.
Any idea how to fix this issue?
I'm guessing the problem is in your "complexTypeName". You wrote "Carrier#Test" when I think you meant to write "Carrier:#Test". The ":#" combination separates the "short name" from the namespace; you omitted the colon.
Hope that's the explanation.

Sort/group NSDictionary by key

i have data in NSDictionary like below :
Value : Football, Key: SPORT
Value : Cricket, Key: SPORT
Value : Fastrack, Key: PRODUCT/SERVICE
Value : Audi USA, Key: CARS
Value : BMW, Key: CARS
Value : Facebook, Key: PRODUCT/SERVICE
Value : TED, Key: WEBSITE
Value : National Geographic, Key: MEDIA/NEWS/PUBLISHING
Value : MyWebProduct, Key: WEBSITE
i want grouping of values according to key. what i need to do in this case or another suitable idea to implement this. I want result to be display something like :
SPORT : Football, Cricket
CARS : Audi, BMW
...
any help appreciable ...
Since you have multiple objects grouped under the same key, a dictionary of arrays would be a suitable structure to contain your data.
NSMutableDictionary *dict = [ [ NSMutableDictionary alloc ] init ];
NSArray *myItems = [ [ NSArray alloc ] initWithObjects:#"item one", #"item two", nil ];
[ dict setObject:myItems forKey:#"group of items" ];
Then you can access the group using
[dict objectForKey:#"group of items"]
Would this work for you, as a category on NSMutableDictionary:
- (void)setObject:(id)object inArrayForKey:(id <NSCopying>)key
{
id current = [self objectForKey:key];
if (!current || ![current isKindOfClass:[NSArray class]]) {
[self setObject:#[object] forKey:key];
} else {
[self setObject:[(NSArray *)current arrayByAddingObject:object] forKey:key];
}
}
Basically, you would then have a clean interface adding an item into an array associated with the key. You could choose to only make it an array if there was more than one item, if that's your preference.
If you're not familiar with adding categories, they allow you to add methods to existing classes. In Xcode just do new file > objective-C category and add the category on NSMutableDictionary.
NSDictionary cannot be sorted by default. If you want sorted dictionary, go on and implement your own subclass of it (this is one of the few valid reasons for which you can subclass a standard container object).

Mapping With Restkit iphone

I am trying to map and store a response json data using restkit object mapping. unfortunately i cannot able to map a response data. when i view my database the datas are storing, but i get a crash with following message..
this class is not key value coding-compliant for the key
Output response
{
"users": [
{
"id": "123456",
"ne": "JohnSmith",
"el": "example#example.com",
"dob": "1985/02/04",
"profile": {
"id": "654321",
"ht": "170cm",
"wt": "70kg"
}
}
]
}
I am using mapping like this
RKManagedObjectMapping *userProfileMapping = [RKManagedObjectMapping mappingForClass:[GHSUser class] inManagedObjectStore:manager.objectStore];
[userProfileMapping mapKeyPath:#"id" toAttribute:#"userId"];
[userProfileMapping mapKeyPath:#"ne" toAttribute:#"name"];
[userProfileMapping mapKeyPath:#"el" toAttribute:#"email"];
[userProfileMapping mapKeyPath:#"dob" toAttribute:#"dob"];
RKManagedObjectMapping *standardProfileMapping = [RKManagedObjectMapping mappingForClass:[GHSProfile class] inManagedObjectStore:manager.objectStore];
[standardProfileMapping mapKeyPath:#"id" toAttribute:#"userId"];
[standardProfileMapping mapKeyPath:#"ht" toAttribute:#"height"];
[standardProfileMapping mapKeyPath:#"wt" toAttribute:#"weight"];
[manager.mappingProvider setMapping:standardProfileMapping forKeyPath:#"users.profile"];
//here in keypath(users.profile) i am getting crash,but profile details are inserting in db. when i change keypath to profile, i am not getting any crash but profile details are not inserting in db.
[userProfileMapping mapRelationship:#"users" withMapping:standardProfileMapping];
Error Message:
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<_NSObjectID_48_2 0x888a8d0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key profile.'
It is because your users parameter is an NSArray, not a NSDictionary. It doesn't know which users.profile to use.
You want to change the same line:
[manager.mappingProvider setMapping:standardProfileMapping forKeyPath:#"users.profile"];
to:
[manager.mappingProvider setMapping:userProfileMapping forKeyPath:#"users"];
and add this line to your userProfileMapping:
[userProfileMapping mapKeyPath: #"profile" toRelationship: #"profile" withMapping: standardProfileMapping]

What's the correct way to map objects in RestKit with the following JSON response

There's 2 parts to this question, both about RestKit:
How can we post up 2 values email and password, and deal with the response using the object mapper
How can we map 2 objects in a response
We are expecting the following JSON response:
{
"code" : 0,
"error_string" : "OK.",
"message" : "OK.",
"token" : {
"app_id" : "1",
"created" : "2011-08-19 11:30:31",
"token" : "ecb8862189974248233dfcc7e8fc1e4514e16972",
"user_id" : "1"
},
"user" : {
"avatar_url" : "",
"created" : "2011-08-19 11:29:21",
"email" : "x#x.com",
"forename" : "Matthew",
"gender" : "M",
}
}
What's the correct way to map this out, we've got a class setup for User and Token, but all the examples i've seen seem to not show something like this where there is two segments to the response, here's the code we have at the moment:
// Mapping for User
RKObjectMapping* userMapping = [RKObjectMapping mappingForClass:[User class]];
[userMapping mapKeyPath:#"created" toAttribute:#"created"];
[userMapping mapKeyPath:#"avatar_url" toAttribute:#"avatarURL"];
[userMapping mapKeyPath:#"gender" toAttribute:#"gender"];
[userMapping mapKeyPath:#"email" toAttribute:#"email"];
[[RKObjectManager sharedManager].mappingProvider setMapping:userMapping forKeyPath:#"user"];
// Mapping for Token
RKObjectMapping* tokenMapping = [RKObjectMapping mappingForClass:[Token class]];
[tokenMapping mapAttributes:#"user_id", #"app_id", #"token", #"created", nil];
[[RKObjectManager sharedManager].mappingProvider setMapping:tokenMapping forKeyPath:#"token"];
// Load the object model via RestKit
[[[RKObjectManager sharedManager] client] setValue:#"xxxxxxxxxxxxxxxxxxx" forHTTPHeaderField:#"X-API-KEY"];
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/users/authenticate/" delegate:self];
Appreciate any help you can give on this, loving RestKit so far!
You should have everything you need configured for this mapping. You probably want to use the didLoadObjectDictionary: delegate call-back so that you can identify the objects by mappable keyPath. Otherwise if you use didLoadObjects:, you should just wind up with an Array with a User & Token object inside of it.

Facebook Graph API: result in array or in json object

I have little bit confuse between graph api result.Can any one explain which default object method is facebook using when we fetch data via graph api. Have any application account setting for access data in json object or in array object, because some time i found user data in encrypted and some time non encrypted.
I found user email id in two way from facebook graph api.
One is:
{
"id": "100001114785800",
"name": "Stella Jackson",
"first_name": "Stella",
"last_name": "Jackson",
"link": "http://www.facebook.com/profile.php?id=100001114785800",
"birthday": "04/16/1987",
"gender": "female",
"email": "stella_ja#live.com",
"timezone": 5.5,
"locale": "en_US",
"updated_time": "2010-10-08T13:26:10+0000"
}
And second one is:
{
"id": "100001114785800",
"name": "Stella Jackson",
"first_name": "Stella",
"last_name": "Jackson",
"link": "http://www.facebook.com/profile.php?id=100001114785800",
"birthday": "04/16/1987",
"gender": "female",
"email": "stella_ja\u0040live.com",
"timezone": 5.5,
"locale": "en_US",
"updated_time": "2010-10-08T13:26:10+0000"
}
Have any idea?
Thanks
The '\u0040' is same as obfuscated or Unicode form of '#' symbol. Most Parsers can convert that to the original symbol.
Check this for list of Unicode character set.
http://www.alanwood.net/demos/ansi.html
#Vik i want to do the same thing, collect post info in array, try this if it work than see..
if (response.authResponse) {
var accessToken = response.authResponse.accessToken;
//var UserInfo = document.getElementById('UserInfo');
FB.api('/' + info.id + '/feed?access_token=' + accessToken,
{ limit: 20 },function(result) {
UserInfo.innerHTML = "Welcome, " + result.id + "!";
alert('Message: ' + result.id);
});
}
Use this to get the dictionary n value of email for ios
FbGraphResponse *fb_graph_response = [fbGraph doGraphGet:#"me" withGetVars:nil];
NSLog(#"getMeButtonPressed: %#", fb_graph_response.htmlResponse);
NSDictionary *dictionary=[fb_graph_response.htmlResponse JSONValue];
NSLog(#"%#",[dictionary valueForKey:#"email"]);
Hope it helps you.
The easiest way would be to take the email string and do something like this (objective c):
NSString *email = #"stella_ja\u0040live.com"; // or whatever you use to get it
email = [NSString stringByReplacingOccurencesOfString:#"\u0040" withString:#"#"];
So in other words, use string methods to replace "\u0040" with "#".
you can simply replace \u0040 with # but during this replace compiler will consider "\" as escape sequence and will skip this without making changes.
What you do like this below:
NSString *strEmail = #"stella_ja\u0040live.com";
[strEmail stringByReplacingOccurrencesOfString:#"\\u0040" withString:#"#"];
NSLog(#"strEmail: %#", strEmail);