I'm trying to understand the restkit 0.22. I got some tutorials from different blogs and youtubes. I ended up with mixed up code.
Could anyone please help me with this, I really need it to work for my project.
I created Core Data Model with entities Songs.xcdatamodeld
I have a json that comes from my mySQL db:
[{"SongID":"1","SongTitle":"Song1","PerformerName":"Performer1","SongURL":"http://mysite/mysongs/1.mp3","PerformerPic":"PerfPic1.png"},
{"SongID":"2","SongTitle":"Song2","PerformerName":"Performer2","SongURL":"http://mysite/mysongs/2.mp3","PerformerPic":"PerfPic2.png"},
{"SongID":"3","SongTitle":"Song3","PerformerName":"Performer3","SongURL":"http://mysite/mysongs/3.mp3","PerformerPic":"PerfPic3.png"}]
in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:http://mysite]];
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Songs" ofType:#"momd"]];
//Initialize managed object store
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL ] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
objectManager.managedObjectStore = managedObjectStore;
[RKObjectManager sharedManager].requestSerializationMIMEType = RKMIMETypeJSON;
[RKMIMETypeSerialization registeredMIMETypes];
[objectManager setAcceptHeaderWithMIMEType:#"application/json"];
RKEntityMapping* mapping = [RKEntityMapping mappingForEntityForName:#"Songs"
inManagedObjectStore:[RKObjectManager sharedManager].managedObjectStore];
mapping.identificationAttributes = #[#"songID"];
[mapping addAttributeMappingsFromDictionary:#{#"id" : #"SongID",
#"songTitle" : #"SongTitle",
#"performerName" : #"PerformerName",
#"songURL" : #"SongURL",
#"performerPic" : #"PerformerPic"}];
return YES;
}
in TableView Controller:
- (void)viewDidLoad
{
[super viewDidLoad];
[RKObjectManager.sharedManager getObjectsAtPath:#"/api.php"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
self.Songs = [mappingResult array];
NSLog(#"It Worked: %#", self.Songs);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"It Failed: %#", error);
}];
}
This is the error I'm getting:
GET 'http://mysite/api.php' (200 OK / 0 objects) [request=3.5566s mapping=0.0000s
total=3.5627s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=1001
"No response descriptors match the response loaded." UserInfo=0xb5920b0
{NSErrorFailingURLStringKey=http://mysite/api.php, NSLocalizedFailureReason=A 200
response was loaded from the URL 'http://mysite/api.php', which failed to match all (0)
response descriptors:, NSLocalizedDescription=No response descriptors match the response
loaded., keyPath=null, NSErrorFailingURLKey=http://mysite/api.php,
NSUnderlyingError=0xb5921b0 "No mappable object representations were found at the key
paths searched."}
First, you don't seem to be creating the managed object contexts as part of your setup code. This will likely cause you issues after you fix your 'main' issue:
Your main issue is quite clearly described in the error message:
which failed to match all (0) response descriptors
I.e. You haven't created any response descriptors.
The Object-mapping guide walks you through the mapping and descriptor creation process (and includes lots more details to boot).
Start with something like:
RKResponseDescriptor *rd = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
then add the mapping to the object manager.
(ensure you're calling createManagedObjectContexts somewhere).
Related
I have the following doubts about the JSON data returned from using both "GET" versus "POST" request. In the following URL JSON DATA, the data is not always updated based on the server changes (eg: database). For example, if I delete all the suggestion records from the database when I had 3 previously, it still returns 3 suggestion records in my JSON response body when I call dataTaskWithRequest.
However, if I change to POST, then the JSON response body will always be updated with the actual records from the server. In my server code (Using CakePHP), I did not check for post or get data. Actually, it was intended to be a GET method, but for some reason, only POST method seems to always fetch the most up to date data from JSON as opposed to GET.
Below is my code from my iOS client, but I'm not too sure if its very useful. I was wondering if there is a cache issue for GET request as opposed to POST request? However, I tried disabling cache for NSURLSessionConfig but it had no impact.
config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
The code base is below:
NSString *requestString = [NSString stringWithFormat:#"%#/v/%#.json", hostName, apptIDHash];
NSURL *url = [NSURL URLWithString:requestString];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if (!error) {
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
NSError *jsonError;
NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError];
[self printJSONOutputFromDictionary:jsonObject];
if (!jsonError) {
block(jsonObject, nil);
}
else{
block(nil, jsonError);
}
}
else{
NSError *statusError = [self createServerUnavailableNSError:httpResp];
block(nil, statusError);
}
}
else{
block(nil, error);
}
}];
[dataTask resume];
In the above code fragment, the JSON body is always showing outdated data.
I really want to understand the issue, and would really appreciate if anyone could explain this issue for me.
Try adding the following request header:
[req addRequestHeader:#"Cache-Control" value:#"no-cache"];
I encountered the same problem as you and adding the above code solved the problem for me.
Taken from ASIHTTPRequest seems to cache JSON data always
For simplicity the Rest API, sends this JSON response-body= { "status" : "ok"}.
I set-up my Restkit mappings like... created a Class called StatusResponse which has one #property (nonatomic, assign) NSString *status;
RKObjectMapping *statusResponseMapping = [RKObjectMapping mappingForClass:[StatusResponse class]];
[statusResponseMapping addAttributeMappingsFromDictionary:#{#"status":#"status"}];
// also tried : [statusResponseMapping addAttributeMappingsFromDictionary:#[#"status"]]; which resulted in same error
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *statusResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:statusResponseMapping method:RKRequestMethodPOST pathPattern:#"status" keyPath:nil statusCodes:statusCodes];
[[RKObjectManager sharedManager] addResponseDescriptor:statusResponseDescriptor];
I'm running a post which is successful, but I get this error back:
NSUnderlyingError=0x17024d440 "No mappable object representations were found at the key paths searched.", keyPath=null, NSLocalizedDescription=No response descriptors match the response loaded.}
response.body={
"status": "ok"
}
Any help with this would be appreciated.
You should try keyPath to #"" and pathPattern as nil, here is piece of Code I am using which is perfectly working fine for me. I am doing exactly same you are trying to do.
RKResponseDescriptor *statusResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[ResponseStatus rkObjectMappingForResponse:YES] method:RKRequestMethodAny pathPattern:nil keyPath:#"" statusCodes:statusCodes];
Because your response descriptor has pathPattern:#"status", the mapping will only be used when you make a request to the status path on your server. That probably isn't what you want.
You should probably use pathPattern:nil.
iOS7 & RESTKit 0.20.3
Below is the URL that I need to hit to get a response from Google Maps APIs (I changed the key):
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=coffee&sensor=true&key=1234&location=0.000000,0.000000&radius=100.000000
When I type the URL above in the browser, I get a JSON back (200 OK)
input is the search string the user provides. I have hard-coded it into the URL above.
The following is what I have tried and get a 404 error:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/placeautocomplete/json?input=%#&sensor=true&key=1234&location=0.000000,0.000000&radius=100.000000", [input stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodGET
pathPattern:#""
keyPath:#"predictions" statusCodes:statusCodeSet];
I have also tried the following that gives an error Code=1001 "No response descriptors match the response loaded." :
NSIndexSet *statusCodeSet = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKMapping *mapping = [TBSRESTMappingProvider googleAutoCompleteMapping];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=coffee&sensor=true&key=1234&location=0.000000,0.000000&radius=100.000000"]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodGET
pathPattern:#""
keyPath:#"predictions" statusCodes:statusCodeSet];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request
responseDescriptors:#[responseDescriptor]];
What's the best practice to provide the complete URL without hard-coding the input sensor location key and radius ?
How can I fix Code=1001 "No response descriptors match the response loaded." ?
The URL path that you request needs to match against the path pattern you supply to the response descriptor. If you want to work the way you are then set the path pattern to nil (which matches everything).
Best practice would generally be to use an RKObjectManager instance and call getObjectsAtPath:parameters:success:failure: and passing a dictionary of parameters that should be appended to the request URL (built from the base URL, path and parameters).
I have a connection issue that I am unsure how to resolve. I have combed through the documentation for the Errors and for NSURLConnection. This is code that I am using in my iOS version of the same app. It works fine there, but when I brought it to the OS X version of the app, it doesn't work. This is the code:
NSURL* url = [NSURL URLWithString:#"url"];
NSString* data = [NSString stringWithFormat:#"command=retrieve&number=%d", number];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"Starting Command");
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog([NSString stringWithFormat:#"%#",connectionError]);
if ([data length] > 0 && connectionError == nil) {
dispatch_async(dispatch_get_main_queue(), ^{
[self parseResponseFromCommandRequest:data];
});
}
}];
NSLog(#"Ending Command");
The error occurs in the NSURLConnection. The output is:
Error Domain=NSPOSIXErrorDomain Code=1 "The operation couldn’t be completed. Operation not permitted" UserInfo=0x610000279dc0 {NSErrorFailingURLStringKey=url, NSErrorFailingURLKey=url}
url is actually a functioning url, but I replaced it here. Like I said, it works fine on iOS, but not on OS X. Is there a Library that I could be missing that is causing this? Any other ideas?
It could be just a matter of setting up the entitlements to allow access. It looks from the error that it fails because it's not permitted, which would indicate the app sandbox is doing it's job. For NSURL you would normally use bookmarks.app-scope or bookmarks.document-scope.
See: Enabling Security-Scoped Bookmark and URL Access
Depending on how your app is using the NSURL, network entitlements may be worth looking into:
com.apple.security.network.server = Allow Incoming Connections
com.apple.security.network.client = Allow Outgoing Connections
I'm working on an iPhone app that needs to load data from my server in JSON or XML format. Since the app is free, I get huge amount of data and I get crash when launching app due to the long time when loading the data. So I understand that I should not get "all" the JSON at once but I have to load the data "pagened" [ little by little ] ..
I found this project that suits well my needs but can't get succes to modify it to my need :
https://github.com/nmondollot/NMPaginator
The project tooks Twitter api as a data source, what if I need to deal with a simple php file that returns JSON formatted data?
nb: I tried to contact the project developer after I tried to modify, but didn't get answer until now.
Thanks.
The easiest solution could be to just download the data in another thread. This can be done in many ways but one way to do it is by using grand central dispatch (GCD).
Something like this
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSURL *url = [NSURL URLWithString:#"Your_URL"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:req
queue:[NSOperationQueue currentQueue]
completionHandler:
^(NSURLResponse *res, NSData *data, NSError *err) {
// Convert the data to appropriate object
NSString* myString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
//You would probably deserialize the json here
//self.tableViewArray = serialiedObjects;
dispatch_async(dispatch_get_main_queue(), ^{
//Reload table view
[self.tableView reloadData];
});
}];
});