restkit: mapping to_many relations with core data - iphone

I'm creating my first RestKit application. I'm trying to map to_many relation to core data.
Speakers JSON
{
id: 1,
session_ids: [1,87]
},
{
id: 2,
session_ids: [2,88]
},
Mapping
sessionEntitiyMapping = [RKEntityMapping mappingForEntityForName:#"Session" inManagedObjectStore:self.managedObjectStore];
[sessionEntitiyMapping addAttributeMappingsFromDictionary:#{
#"id": #"session_id",
}];
sessionEntitiyMapping.identificationAttributes = #[ #"session_id" ];
speakerEntityMapping = [RKEntityMapping mappingForEntityForName:#"Speaker" inManagedObjectStore:self.managedObjectStore];
[speakerEntityMapping addAttributeMappingsFromDictionary:#{
#"name": #"name",
#"id": #"speaker_id",
}];
[speakerEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"session_ids"
toKeyPath:#"sessions"
withMapping:sessionEntitiyMapping]];
speakerEntityMapping.identificationAttributes = #[ #"speaker_id" ];
Error
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFNumber 0x8569690> valueForUndefinedKey:]: this class is not key value coding-compliant for the key id.'

I think the problem is that you are using a primitive in your model, i.e session_id has NSInteger type. Unfortunately you are disallowed to use it, please use NSNumber instead.

Related

Issue with fetching core data objects using NSPredicate

Before I start let me give you how my data model looks like:
I then have a fetch request with the following predicate:
NSArray *allowedPackNames = #[#"success, happiness, free"];
self.fetchedResultsController = [Author MR_fetchAllGroupedBy:nil
withPredicate:[NSPredicate predicateWithFormat:#"ANY quotes.quote.pack.packName IN %#", allowedPackNames]
sortedBy:AuthorKeys.name
ascending:YES
delegate:self];
I wanted to fetch all Authors that has a Quote with packName of success or happiness or free.
Author has a NSSet of quotes as you can see in the relationship table below. However when I execute this I get the following error:
CoreData: error: (1) I/O error for database at /Users/Abdul/Library/Application Support/iPhone Simulator/6.1/Applications/DA17421B-A54D-42E3-9694-FDCBFF7F8BA4/Library/Application Support/MyCoolApp/MyCoolApp.sqlite. SQLite error code:1, 'no such column: t2.ZQUOTE'
2013-04-05 15:26:47.175 MyCoolApp[78622:c07] Core Data: annotation: -executeRequest: encountered exception = I/O error for database at /Users/Aditya/Library/Application Support/iPhone Simulator/6.1/Applications/DA17421B-A54D-42E3-9694-FDCBFF7F8BA4/Library/Application Support/MyCoolApp/MyCoolApp.sqlite. SQLite error code:1, 'no such column: t2.ZQUOTE' with userInfo = {
NSFilePath = "/Users/Abdul/Library/Application Support/iPhone Simulator/6.1/Applications/DA17421B-A54D-42E3-9694-FDCBFF7F8BA4/Library/Application Support/MyCoolApp/MyCoolApp.sqlite";
NSSQLiteErrorDomain = 1;
}
Any idea why?
If I see it correctly, the predicate should be
[NSPredicate predicateWithFormat:#"ANY quotes.pack.packName IN %#", allowedPackNames]
i.e. you have to remove "quote", which is an attribute of the Quote entity, not a relationship.

Extracting Data from NSMuableDictionary to NSString and compering to String issue

Im Extracting Data from NSMuableDictionary to NSString and try compering to String like this:
NSDictionary *error = [[NSDictionary alloc]init];
NSString *errorCode = [[NSString alloc]init];
error = [sing.globalCallsDitionary valueForKey:#"Error"];
NSLog(#"error code %#",[error valueForKey:#"error_code"]);
errorCode = [error valueForKey:#"error_code"];
if ([errorCode isEqualToString:#"-1"]) {
When the if statement executed i get this error talking about an array, the error looks like this:
2012-04-27 06:34:49.686 CallBiz[10319:707] error code (
"-1"
)
2012-04-27 06:35:00.602 CallBiz[10319:707] -[__NSArrayI isEqualToString:]: unrecognized selector sent to instance 0x16fc10
2012-04-27 06:35:00.608 CallBiz[10319:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI isEqualToString:]: unrecognized selector sent to instance 0x16fc10'
*** First throw call stack:
(0x3541f88f 0x36846259 0x35422a9b 0x35421915 0x3537c650 0xb2a3 0x353793fd 0x32458faf 0x32458f6b 0x32458f49 0x32458cb9 0x324595f1 0x32457ad3 0x324574c1 0x3243d83d 0x3243d0e3 0x3667222b 0x353f3523 0x353f34c5 0x353f2313 0x353754a5 0x3537536d 0x36671439 0x3246be7d 0x2e61 0x28fc)
terminate called throwing an exception
It is as xCode is looking on my NSString *errorCode = [[NSString alloc]init]; as if it is an NSArray, can someone help me with this?
Error occurs because your errorCode came as a array, instead of string. If you are sure that only 1 object come here, then you can use -
if ([[errorCode objectAtIndex:0] isEqualToString:#"-1"])
It will work, although it will through a warning, because errorCode is defined as a string object. So you ned to sure what data you are getting in response and then define data structure appropriately.

Core Data NSSet returning empty array of objects

UPDATE: I had ghost entries in my database of games without players from before I implemented Players at all. It was returning those entries not the latest entries with the updated Model
I am working to get a Core Data database working and having some trouble with relationships. I'm very new to the whole thing so don't put anything past me I may no even understand the basics. But here we go anyway.
This is where I create a new Game Entity. The Players is a to-may relationship to Several Player entities that were selected and stored in an array.
Game *newGame = [NSEntityDescription insertNewObjectForEntityForName:#"Game" inManagedObjectContext:[SDDataManager dataManager].managedObjectContext];
[newGame setGameType:#"multipleChoice"];
[newGame setDate:[NSDate date]];
NSSet *playersSet = [NSSet setWithArray:players];
[newGame setPlayers:playersSet];
[newGame setCards:[NSKeyedArchiver archivedDataWithRootObject:selectedCards]];
NSError *error;
[[SDDataManager dataManager].managedObjectContext save:&error];
NSLog(#"New Game Error: %#",[error localizedDescription]);
The problem is that when I call it out of the database like this:
NSFetchRequest *requestSavedGame = [NSFetchRequest fetchRequestWithEntityName:#"Game"];
[requestSavedGame setFetchLimit:1];
NSError *error;
NSArray *loadedGame = [[SDDataManager dataManager].managedObjectContext executeFetchRequest:requestSavedGame error:&error];
NSLog(#"Load Game Error: %#",[error localizedDescription]);
Game *game = [loadedGame objectAtIndex:0];
NSLog(#"Players Set: %#",game.players);
NSLog(#"Players: %#",[game.players allObjects]);
The Players: is empty?? It returns this exactly:
Players Set: Relationship 'players' fault on managed object (0xd023b70) <Game: 0xd023b70> (entity: Game; id: 0xd023180 <x-coredata://E6A82377-31D2-4D11-B890-B3FDC5A03E0E/Game/p1> ; data: {
cards = <62706c69 73743030 d4010203 0405086e 6f542474 6f705824 6f626a65 63747358 24766572 73696f6e 59246172 63686976 6572>;
currentPlayer = 0;
date = "2012-03-27 18:20:07 +0000";
gameType = multipleChoice;
players = "<relationship fault: 0xd01fd60 'players'>";
})
Players: ( )
I have no understanding why the players is a full array, then a full set when it goes in but when it comes out the [set allobjects] returns an empty array...
I would suggest you to use valueForKey for whatever key.
In core data fault is not an error, it means you are trying to access from core data which does not exist. and i would say you should use setPropertiesToFetch which specifies which properties should be returned by the fetch.
The message saying that it is a fault does not mean that it is empty. It simply means that the data has not been loaded from the database. If you access it like normal, you should see your data there. Try this and see what it says:
NSLog(#"Players count: %i", [game.players count]);
Read about faults here: Core Data Programming Guide - Faulting and Uniquing

IOS - RESTKIT - mapping result in multiple ways

I am new to ios/RESTKIT. I am trying to consume a webservice from an ios device using RESTKIT. The json return could have 2 possible outcomes.
A) On Failure, json result looks like this (result is a string "null". Error code available):
{
status: false,
result: null
error: NO_SUCH_USER
}
Mapping for (A)
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[WsReturn class]];
[mapping mapKeyPath:#"result" toAttribute:#"result"];
[mapping mapKeyPath:#"status" toAttribute:#"status"];
[mapping mapKeyPath:#"error" toAttribute:#"error"];
[objectManager.mappingProvider setMapping:mapping forKeyPath:#"/"];
B) On Success, it looks like (result is a "complex object". Error code is null):
{
status: true,
result: {
name: "Some User",
tasks: [
{
name: "Some Task1",
taskId: 10
},
{
name: "Some Task2",
taskId: 20
}
]
},
error: null
}
Mapping for (B)
RKObjectMapping* taskMapping = [RKObjectMapping mappingForClass:[Task class]];
[taskMapping mapKeyPath:#"name" toAttribute:#"name"];
[taskMapping mapKeyPath:#"taskId" toAttribute:#"taskId"];
[objectManager.mappingProvider setMapping:taskMapping forKeyPath:#"tasks"];
RKObjectMapping* resultMapping = [RKObjectMapping mappingForClass:[Result class]];
[resultMapping mapKeyPath:#"name" toAttribute:#"name"];
[resultMapping mapRelationship:#"tasks" withMapping:taskMapping];
[objectManager.mappingProvider setMapping:resultMapping forKeyPath:#"result"];
RKObjectMapping* cmplxMapng = [RKObjectMapping mappingForClass:[WsReturn class]];
[cmplxMapng mapKeyPath:#"status" toAttribute:#"status"];
[cmplxMapng mapKeyPath:#"error" toAttribute:#"error"];
[cmplxMapng mapRelationship:#"result" withMapping:resultMapping];
[objectManager.mappingProvider setMapping:cmplxMapng forKeyPath:#"/"];
Questions
1) (A) works alright. (B) does not. Can you provide some pointers?
2) For the same webservice call, "result" part could be a string (null) or a complex object. So how do I handle this in code? Which mapping do I pass? mapping or cmplxMapng (name changed to avoid horozontal scroll)?
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/myUrl"
objectMapping:HOW_TO_DECIDE_WHICH_MAPPING_TO_PASS_HERE delegate:self];
I believe this is a common scenario. I searched, but couldn't find related examples. Maybe I looked in the wrong places. Thoughts/pointers on how to approach this will help. Thanks.
So this is how I solved it -
1) I replaced this line:
[objectManager.mappingProvider setMapping:taskMapping forKeyPath:#"tasks"];
with this: (notice forKeyPath)
[objectManager.mappingProvider setMapping:uooMapping forKeyPath:#"result.tasks"];
2) Followed this thread http://groups.google.com/group/restkit/browse_thread/thread/89b25b3f0f7e0177 & added this line as suggested by Blake:
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.3]];
just before call to loadObjectsAtResourcePath
3) As for mapping the objects in different ways, I found that passing cmplxMapng always seems to work.
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/myUrl"
objectMapping:cmplxMapng delegate:self];
So if the "result" part comes back as the string "null", I get "(null)" for result & "status" & "error" fields are mapped correctly. Works!
Hope this helps someone.

Why an NSException error?

I have put the following code in...;
NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:#"text/plain",kSKPSMTPPartContentTypeKey,
#"Hello,\n You've just received a new message from the iDHSB iPhone App.\n Here it is: %#",field.text,
kSKPSMTPPartMessageKey,#"8bit",kSKPSMTPPartContentTransferEncodingKey,nil];
...and I receive an NSException error saying;
*** WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate:
<NSInvalidArgumentException> +[NSDictionary dictionaryWithObjectsAndKeys:]: second object of each pair must be non-nil. Or, did
you forget to nil-terminate your parameter list?
What does this mean? What do I have to do to fix this issue?
Thanks,
James
You are trying to format a string in your dictionary initialization and it expects the format to be object, key, object, key, etc... To fix try creating your formatted string on another line for clarity and then adding it as part of the objects and keys as so
NSString *message = [NSString stringWithFormat:#"Hello,\n You've just received a new message from the iDHSB iPhone App.\n Here it is: %#",
field.text];
NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:
#"text/plain", kSKPSMTPPartContentTypeKey,
message, kSKPSMTPPartMessageKey,
#"8bit", kSKPSMTPPartContentTransferEncodingKey,nil];
Maybe you meant something like this:
NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:#"text/plain", kSKPSMTPPartContentTypeKey, [NSString stringWithFormat:#"Hello,\n You've just received a new message from the iDHSB iPhone App.\n Here it is: %#",field.text], kSKPSMTPPartMessageKey, #"8bit", kSKPSMTPPartContentTransferEncodingKey,nil];
You are missing an argument. I count 8 total arguments including nil. That means one of your key value pairs is not complete.
Try firsty create string:
NSString *partMessageKey = [NSString stringWithFormat:#"Hello,\n You've just received a new message from the iDHSB iPhone App.\n Here it is: %#",field.text];
then put this string to dictionary as object.