I'm having a little trouble with RestKit.
First I tried to use just RKClient:
[RKClient clientWithBaseURL:[defaults stringForKey:#"myURL"]];
But I was getting errors thrown by NSManagedObject+ActiveRecord.m (similar to this). So I ended up creating a RKObjectManager (though I don't plan on using it):
RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:[defaults stringForKey:#"orangeqcURL"]];
manager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:#"OrangeQC.sqlite"];
[RKObjectManager setSharedManager:manager];
But I'm not able to get a basic call to work:
[RKClient sharedClient].username = self.login;
[RKClient sharedClient].password = self.password;
[[RKClient sharedClient] get:#"/users" delegate:self];
It give me a url error with two urls:
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo=0x825f2e0 {NSErrorFailingURLStringKey=//mydomain.com/mydomain.com/users, NSErrorFailingURLKey=//mydomain.com/mydomain.com/users, NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x8204230 "unsupported URL"}
Any idea why it would double it?
When I print out the base url it looks right:
NSLog(#"rkclient url: %#",[[RKClient sharedClient] baseURL]);
> rkclient url: mydomain.com/
Any help would be appreciated. Thank you.
Related
I'm writing a simple Twitter app for OS X and I'm currently stuck on downloading the user's profile image. This is the code responsible for downloading the image:
let imageRequest: NSURLRequest = NSURLRequest(URL: NSURL(string: avatarURL)!)
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let dataTask = session.dataTaskWithRequest(imageRequest) {
(data, response, error) in
println(error)
if data != nil {
println("Got image")
let image = NSImage(data: data!)
completion(image)
} else {
println("Data is nil")
completion(nil)
}
}
dataTask!.resume()
avatarURL is a String containing this: https://pbs.twimg.com/profile_images/618168482086129664/C0E92y7G.png, which is the URL to my Twitter avatar. As you can see, it's a perfectly valid URL leading to a perfectly valid image.
But whenever I run my app, the println(error) line prints this into my console:
Optional(Error Domain=NSURLErrorDomain Code=-1002 "The operation couldn’t be completed. (NSURLErrorDomain error -1002.)" UserInfo=0x61000006ea80 {NSErrorFailingURLStringKey=Optional(https://pbs.twimg.com/profile_images/618168482086129664/C0E92y7G.png), NSUnderlyingError=0x600000243720 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1002.)", NSErrorFailingURLKey=Optional(https://pbs.twimg.com/profile_images/618168482086129664/C0E92y7G.png)})
Am I doing something wrong? I've already googled (what a word) this, and almost every single SO page I've found has a solution that basically amounts to "Your URL is missing an URL scheme/has an unsupported URL scheme", which is not the problem I'm having.
I finally figured out how to fix this. Before, I just lazily did this:
var avatarURLString = String(responseObject["profile_image_url_https"])
which apparently returns an Optional that can't be unwrapped with an exclamation mark. Yes, I don't know either. It's just what happened.
Now, I do this:
var avatarURLString = responseObject["profile_image_url_https"] as! String
...which actually yields a proper String object instead of some weird not-quite-Optional. Hooray for using beta versions of programming languages.
I have a trouble, I have a folder url, folder, that stored on that url path is exist and it's ok. Problem is that contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error: returns with an error.
My NSURL to folder is NSString, that made from another method that take NSURL and save it as absoluteString object.
Here is my code:
NSURL *folderURL = [NSURL fileURLWithPath:folderPathString isDirectory:YES];
if ([folderURL isFileURL]) {
NSLog(#"it's file"); // I see this in console
}
NSError *error;
// array of NSURL objects
NSArray *contentOfFolder = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:folderURL
includingPropertiesForKeys:#[NSURLContentModificationDateKey,NSURLFileResourceTypeKey, NSURLLocalizedNameKey]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:&error];
if (error) {
NSLog(#"%#",error);
}
This is a part of my method, in console, I see an error:
Error Domain=NSCocoaErrorDomain Code=260 "The file “myFolder” couldn’t be opened because there is no such file." UserInfo=0x10051b0a0 {NSURL=file:/localhost/Users/myUser/myRootFolder/myFolder/ -- file://localhost/Users/myUser/Library/Developer/Xcode/DerivedData/myProject-algooymkavrtmlchwnlbrmvcbvzj/Build/Products/Debug/, NSFilePath=/Users/myUser/Library/Developer/Xcode/DerivedData/myProject-algooymkavrtmlchwnlbrmvcbvzj/Build/Products/Debug/file:/localhost/Users/myUser/myRootFolder/myFolder, NSUnderlyingError=0x100526f40 "The operation couldn’t be completed. No such file or directory"}
I don't understand why I get this error. How I can get No such file or directory error, if this directory exist?!
EDIT
I found that after method fileURLWithPath:isDirectory: my folder url looks strange, when I look at it with NSLog.
NSLog(#"folder url %#",folderURL);
output:
folder url file:/localhost/Users/myUser/myRootFolder/myFolder/
-- file://localhost/Users/myUser/Library/Developer/Xcode/DerivedData/myProject-algooymkavrtmlchwnlbrmvcbvzj/Build/Products/Debug/
Why the second part is appear? (part that starts with -- file://localhost/Users/myUser/Library/...). I think problem with this but what I do wrong? Is method fileURLWithPath:isDirectory: don't acceptable for my purposes?
The folderPathString in
NSURL *folderURL = [NSURL fileURLWithPath:folderPathString isDirectory:YES];
must be a simple path, e.g. "/path/to/dir". In your case, it is a string URL "file://localhost/path/to/dir", which is wrong.
I assume that folderPathString is created from some NSURL using
folderPathString = [anURL absoluteString];
This is wrong and should be
folderPathString = [anURL path];
It might also be possible to avoid the conversion from URL to string and back to URL
altogether.
I'm new to RestKit so this question may be dumb: When using [objectManager sendObject:...], how do I tell RestKit which mapping it should use for the result? More specific: I am sending GET and POST data to a server which in return responds with a JSON encoded message:
{"purchaseresult":{"status":"ok","errormsg":""}}
The Objective-C code I use looks like this:
RKObjectMapping *purchaseResultMapping = [RKObjectMapping mappingForClass:[PurchaseResult class]];
[purchaseResultMapping mapKeyPathsToAttributes:#"status", #"status", #"errormsg", #"errorMessage",nil];
[objectManager.mappingProvider setMapping:purchaseResultMapping forKeyPath:#"purchaseresult"];
[[RKObjectManager sharedManager].mappingProvider setErrorMapping:purchaseResultMapping];
[objectManager sendObject:queryParams toResourcePath:#"/purchase/post" usingBlock:^(RKObjectLoader* loader) {
loader.method = RKRequestMethodPOST;
loader.resourcePath = #"/purchase/post";
loader.params = queryParams;
loader.objectMapping = purchaseResultMapping;
}];
This returns an RestKit error:
restkit.network:RKObjectLoader.m:216 Encountered errors during mapping: Expected an object mapping for class of type '__NSDictionaryI', provider returned one for 'PurchaseResult'
Any ideas what I am doing wrong here?
Thanks
Christian
The object that you're sending is a NSDictionary so RestKit is looking for an object mapping for an NSDictionary but you are providing a PurchaseResult mapping. If you send an instance of PurchaseResult or provide your mapping for the NSDictionary class then this error should be avoided.
An alternative to this would be as follows:
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/purchase/post" usingBlock:^(RKObjectLoader *loader) {
loader.delegate = **Your loader delegate here**;
loader.method = RKRequestMethodPOST;
loader.params = queryParams;
}];
Just make sure you've defined your mapping for the objects coming back in and you should be good.
I am trying to migrate to RestKit 0.20-pre2.
Currently I managed to migrate my mapping (at least the compiler does not complain anymore), but I have problems in creating requests (previously I used the RKObjectLoader which does not exist anymore.
My previous code is the following:
- (RKObjectLoader*)objectLoaderWithResourcePath: (NSString*)resourcePath
method: (RKRequestMethod)httpMethod
parameters: (NSDictionary*)parameters
mappableClass: (Class)objectClass
{
RKObjectMapping *mapping = [self.objectManager.mappingProvider objectMappingForClass:objectClass];
NSString *path = resourcePath;
if (httpMethod == RKRequestMethodGET) {
path = [resourcePath stringByAppendingQueryParameters:parameters];
}
RKObjectLoader *request = [self.objectManager loaderWithResourcePath:path];
request.method = httpMethod;
request.delegate = self;
request.objectMapping = mapping;
if (httpMethod != RKRequestMethodGET) {
request.params = parameters;
}
return request;
}
I used the above method to create a generic request, and then send it either synchronously or asynchronously.
Now... I saw the new method getObjectsAtPath: parameters: success: failure:, but.. I need the same for the POST (and I don't have any object to post... it is simply the server which accept a POST request for the login..)
Any help?
Thank you
I had the same problem as you and i received a great answer here:
Trying to make a POST request with RestKit and map the response to Core Data
Basically,
This is what you need:
NSDictionary *dictionary = #{ #"firstParam": #(12345), #"secondParam": #"whatever"};
NSMutableURLRequest *request = [objectManager requestWithObject:nil method:RKRequestMethodPOST path:#"/whatever" parameters:parameters];
RKObjectRequestOperation *operation = [objectManager objectRequestOperationWithRequest:request ^(RKObjectRequestOperation *operation, RKMappingResult *result) {
NSLog(#"Loading mapping result: %#", result);
} failure:nil];
There is an example here in README section Managed Object Request that will help you:
https://github.com/RestKit/RestKit
You can use AFNetworking directly using the RK HTTPClient subclass, something like this:
[[RKObjectManager sharedManager].HTTPClient postPath:#"/auth" parameters:params success:^(AFHTTPRequestOperation *operation, id JSON)
{
// Success
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// Error
}];
Since RestKit v0.20.x, RK now use AFNetworking under the hood instead of RKClient, so you can refer directly to the AFNetworking docs:
http://afnetworking.github.com/AFNetworking/Classes/AFHTTPClient.html#//api/name/postPath:parameters:success:failure:
Edit
In my project, for the auth, I simply created an NSObject named User, with a singleton, and managed the mapping myself. I (personally) didn't need to have my auth user in my core data stack. If you need to use the RK Core data mapping capabilities, take a look at RKObjectManager with the postObject:path:parameters:success:failure: method.
Back before 0.10.0 both 'error' and 'errors' messages 'just worked' with RestKit. I see that in 0.10.0 you can set the rootKeyPath for the error mapping.
objectManager.mappingProvider.errorMapping.rootKeyPath = #"errors";
However I can only set it to error xor errors. To me this seems like a regression. What am I missing?
This is what I have to manage errors:
#import <RestKit/RKErrorMessage.h>
...
//configure error manager
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping mapKeyPath:#"message" toAttribute:#"errorMessage"];
[objectManager.mappingProvider setErrorMapping:errorMapping];
In 0.10.0 RestKit added the error context which only tries to map the response to an error mapping if the status code is 4xx or 5xx but they only allow for one top level key path (as far as I know). Thus I couldn't map both 'errors' and 'errors'. I tried to fix this without modifying restkit but I had to modify one line which you can see in my branch
https://github.com/stevemoser/RestKit/tree/fix-errors-context
Then when I setup my error mapping it looks like this:
#import <RestKit/RKErrorMessage.h>
#import <RestKit/RKObjectMappingProvider+Contexts.h>
[objectManager.mappingProvider setErrorMapping:nil];
[objectManager.mappingProvider setValue:[NSMutableDictionary dictionary] forContext:RKObjectMappingProviderContextErrors];
RKObjectMapping* errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping mapKeyPath:#"" toAttribute:#"errorMessage"];
[objectManager.mappingProvider setMapping:errorMapping forKeyPath:#"error" context:RKObjectMappingProviderContextErrors];
[objectManager.mappingProvider setMapping:errorMapping forKeyPath:#"errors" context:RKObjectMappingProviderContextErrors];