getting JSON data without object mapping using RestKit 0.2 - iphone

I'm trying to call a RESTful web service with RESTKit 0.2 that returns only a string, but the RKResponseDescriptor class forces me to use a mapping with its method responseDescriptorWithMapping in order to be able to get the string value, I created the mapping and got the string value without any problems, but how can i get this string value without having to create the object mapping (i.e. creating an NSObject subclass, creating a property for the string to be received, and creating a mapping dictionary between the returned JSON key and this property) ?

You can still use RestKit to make the request. Sometimes it makes sense to do so in case server is returning an error for example, in which case it is necessary to access the raw data returned from server.
[[RKObjectManager sharedManager] getObjectsAtPath:kLoginURL
parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSError *error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:operation.HTTPRequestOperation.responseData options:NSJSONReadingMutableLeaves error:&error];
NSLog(#"msg: %#", [json objectForKey:#"msg"]);
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];

In this case, don't use RestKit to make the request. RestKit uses AFNetworking for the underlying network communications so if you import the classes you can use it too. Try directly using AFHTTPRequestOperation to make the request.

Related

Restkit request load handler

As i see in all RestKit documentations, didWSRequestLoadObjects delegate function is used to handle service response.
The problem is, if I have a different requests (postObject) in my view controller i have to check response type in didWSRequestLoadObjects for each request.
Is there a way to register a function before each postObject and get each response in different function?
Which version of RestKit are you using?
On the last release it is highly encouraged to use blocks instead of a loadObjects delegate function. For example, the RKObjectManager postObject method has a success and error parameters which receives a block.
Here is an example of use:
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://some.url"];
//Configure here your manager with response descriptors and stuff..
[manager postObject:someObject path:#"/some/path" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
//Success Response code here
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
//Error Response code here
}];

EXC_BAD_ACCESS -iPhone Objective c

I've been trying this Twitter api stuff and it's really confusing...
I keep getting EXC_BAD_ACCESS bad access with the following code... What is the problem here?
NSURL *followingURL = [NSURL URLWithString:#"https://api.twitter.com/1/users/lookup.json"];
// Pass in the parameters (basically '.ids.json?screen_name=[screen_name]')
id fromIntToNum = [NSNumber numberWithInteger: friID];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:#"159462573", #"user_id", nil];
// Setup the request
twitterRequest = [[TWRequest alloc] initWithURL:followingURL
parameters:parameters
requestMethod:TWRequestMethodGET];
// This is important! Set the account for the request so we can do an authenticated request. Without this you cannot get the followers for private accounts and Twitter may also return an error if you're doing too many requests
[twitterRequest setAccount:theAccount];
// Perform the request for Twitter friends
[twitterRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (error) {
/*
// deal with any errors - keep in mind, though you may receive a valid response that contains an error, so you may want to look at the response and ensure no 'error:' key is present in the dictionary
NSLog(#"%#",error);*/
} else {
/*NSError *jsonError = nil;
// Convert the response into a dictionary
NSDictionary *twitterGrabbedUserInfo = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONWritingPrettyPrinted error:&jsonError];
// Grab the Ids that Twitter returned and add them to the dictionary we created earlier
NSLog(#"%#", [twitterGrabbedUserInfo objectForKey:#"screen_name"]);*/
}
}];
I separated the line the my code fails on...
What could be causing this Twitter API problem?
The following line causes the crash:::
[twitterRequest performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse, NSError *error) {
I will also sometimes get this error:
[__NSCFNumber credentialForAccount:]: unrecognized
UPDATE: I commented out the handler and I made TwitterRequest and ivar, but it still crashes...
In your block you look for an error, but if you get one you log it and continue on. You should put an "else" statement in and only proceed if no error.
Why not try to comment out all your code in the handler - don't do anything - and see if you get the crash. Then try with just the error code. Then try with the JSON serialization, and finally the last line. If you can find the part of the block that is causing the problem that would help.
Also, I suspect that performRequestWithHandler: does not block, but expects you to notify your class within the block that the request is done. If so it means "TWRequest *twitterRequest" should be an ivar or property, and you need to allows for some method to get called when the handler is done. Your crash may be due to ARC reallocating your object while the object is running.
EDIT:
Note that that the TWRequest class description says: "Use the initWithURL:parameters:requestMethod: method to initialize a newly created TWRequest object passing the required property values. " It says PLURAL properties, meaning more than 1. Could it be that it also expects a "credentialForAccount" property? You have to read the twitter docs to find all the required properties.
EDIT2:
Well, we don't even know if you get as far as your handler. Put a NSLog there but I suspect its never getting that far. If true this leaves three possibilities:
a) it does't like the URL (although this seems good)
b) you are missing some parameters it expects
c) id doesn't like "theAccount" object - is it a valid ACAccount object? Try NSLogging it.
It has to be one of these three things.
I had similar issues with iOS5 and TWRequest, and the problem turned out to be the ACAccountStore being released before the request handler block was called. The following code fixed this for me:
__weak ACAccountStore *wAccountStore = accountStore;
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
__strong ACAccountStore *sAccountStore = wAccountStore;
// handle the finished request here
// to silence Xcode warning 'unused variable'
// not necessary for releasing sAccountStore,
// it will go out of scope anyway when the block ends
sAccountStore = nil;
}];
This way, the accountStore gets retained until the block finishes.

How to insert NS Mutable Array into Core Data

-(void)dataManagerDidFinishLoading:(DataManager *)datamgr
{
NSLog(#"%#.....",datamgr);
pageArray=[datamgr.resultDataDictionary objectForKey:#"POS_GetPageResult"];
GetPage *page=(GetPage *)[NSEntityDescription
insertNewObjectForEntityForName:#"GetPage"
inManagedObjectContext:managedObjectContext];
NSError *error;
if (![managedObjectContext save:&error]) {
// This is a serious error saying the record could not be saved.
// Advise the user to restart the application
NSLog(#"Error........");
}
[pageArray insertObject:page atIndex:0];
}
Use NSKeyedArchiver:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
Note that all the objects in array must conform to the NSCoding protocol. If these are custom objects, then that means you need to read up on Encoding and Decoding Objects. You can store the NSData as BLOB in the database. Hope this helps you.
You can use the transformable core data type. Then your object will be parsed to an id. Just keep in mind that the transformable attribute will be passed to a NSData object (and reversed) to be stored (or retrieved) in core data.

convert Core Data NSManagedObject in to JSON on iPhone?

I was to post some of my COre Data objects back to a web service and would like to send them as JSON. I am receiving objects from the server a JSON using this library:
http://code.google.com/p/json-framework/
But I cannot figure out how to change my objects back to JSON?
To create json from you r objects, you have to build an NSDictionary from your object, and then convert to string with the SBJsonWriter class.
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObject:(NSArray *)YourArrayOfElements forKey:#"objects"];
SBJsonWriter *jsonWriter = [SBJsonWriter new];
//Just for error tracing
jsonWriter.humanReadable = YES;
NSString *json = [jsonWriter stringWithObject:jsonDictionary];
if (!json){
NSLog(#"-JSONRepresentation failed. Error trace is: %#", [jsonWriter errorTrace]);
}
[jsonWriter release];
NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding];
And then you can set as your post request's body.
If you would like a more full-featured solution that what is offered by a standalone parsing library, you may want to take a look at RestKit: http://restkit.org/
The framework wraps the operations of fetching, parsing, and mapping JSON payloads into objects. It also allows you to update remote representations by POST/PUT'ing the objects back with a request. By default, outbound requests are form-encoded but the library ships with a class for using JSON as the wire format for posting back to the server.
At a high level, here's what your fetch & post operations would feel like in RestKit:
- (void)loadObjects {
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[#"/path/to/stuff.json" delegate:self];
}
- (void)objectLoader:(RKObjectLoader*)loader didLoadObjects:(NSArray*)objects {
NSLog(#"These are my JSON decoded, mapped objects: %#", objects);
// Mutate and PUT the changes back to the server
MyObject* anObject = [objects objectAtIndex:0];
anObject.name = #"This is the new name!";
[[RKObjectManager sharedManager] putObject:anObject delegate:self];
}
The framework takes care of the JSON parsing/encoding on a background thread and let's you declare how attributes in the JSON map to properties on your object. Mapping to Core Data backed classes is fully supported.

Parse JSON collection from Rails in Objective-C on iPhone

I'm using TouchJSON to parse the output of a JSON Rails API, but am having difficulties. The overall goal is to loop through the response, parse the JSON, create a Round instance for each JSON object, and stick those Round objects into an NSArray so I can load this into a UITableView. So if there's a more straight-forward way to do that than what I'm about to show (which currently is NOT working, btw) please let me know.
The Rails API is returning a collection that looks something like this:
[
{
"round": { "course_title": "Title A", "result": "+8" }
},
{
"round": { "course_title": "Title B", "result": "+4" }
},
...
]
I'm also using ASIHTTPRequest and I can successfully get the response using:
NSString *responseString = [request responseString];
But from there, I cannot seem to get anywhere. Here's more-or-less what TouchJSON suggests:
NSString *jsonString = [request responseString]; // [{"round":{...}}, ..., {"round:{...}}]
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSDictionary *dictionary = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:nil];
// then I do this...
NSLog(#"JSON: %#", dictionary); // JSON: null
I thought from there I would be able to loop through the dictionary and create the object mappings using my Round class. But maybe that's the wrong approach altogether.
My thoughts are that the JSON being returned from Rails is an array of JSON objects, so maybe that's why the JSON parser doesn't recognize it as valid JSON? From this, I have two questions:
1) Should TouchJSON be able to accept an array of JSON objects like what my API is returning?
2) Is it possible to cast the responseString to an NSArray so I can loop through each "round" and parse the JSON that way? If I remove the first and last characters from the response string (i.e. "[" and "]") the JSON parser will only grab the first "round" in the collection.
3) Am I going about this whole process correctly?
Any tips/advice would be much appreciated.
TouchJSON presents three main ways to go from JSON to an Obj-C object. They are all present in the header for CJSONDeserializer which you're already using:
- (id)deserialize:(NSData *)inData error:(NSError **)outError;
- (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError;
- (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError;
The first one will return return whatever, either a dictionary, array, string or whatever the root type of the JSON is.
The other two expect a dictionary or an array and will complain (i.e. return nil and give you an NSError) if they don't get the right data.
The deserializeAsDictionary:error: method of CJSONDeserializer relies on the scanJSONDictionary:error: method of CJSONScanner. This method expects the "dictionary" to be an object literal. Therefore, your data must start with a {. Since your data is an array, you would want to use the deserializeAsArray:error: method of CJSONDeserializer.
Read the documentation carefully, your code is incorrect. It should look like this:
NSData *jsonData = [request responseData]
NSArray *rounds = [[CJSONDeserializer deserializer] deserialize:jsonData error:nil];
// then I do this...
NSLog(#"JSON: %#", rounds);
You could also have used:
NSArray *rounds = [[CJSONDeserializer deserializer] deserializeAsArray:jsonData error:nil];
However your absolute BIGGEST mistake was passing nil for error. You could have avoided going to stackoverflow at ALL if you had passed something in for NSError and then checked that.
With the right tools, this is WAY simpler than you're making it. I do this sort of thing all the time.
Use Stig's JSON framework, and import the NSString category that provides the JSONValue method.
Then inside your ASIHTTPRequest response handler code, go thusly:
NSMutableArray *roundlist = [NSMutableArray array];
NSArray *results = [[request responseString] JSONValue];
for (NSDictionary *item in results) {
Round *myRound = [item objectForKey:#"round"];
//don't actually do the above. Do whatever you do to instantiate a 'Round'.
[roundlist addObject:myRound];
}
[self.tableView reloadData];
EDIT: Geezo. Objection noted re valueForKey: vs objectForKey:. I updated my code sample, and I think we all learned something here.
I also didn't mean any offense with the phrase "with the right tools". OP was looking to simplify his code, and the RIGHT TOOL for that is the library with the simplest interface. I have nothing against TouchJSON per se, but JSON Framework has the simpler interface.