Alright I've been debugging the whole day but can't figure out what the problem is with my code.
The goal is to send a POST with RestKit to the Heroku API with a username/password to retrieve the API key.
The problem is that I'm only able to sent the request once. When sending the request the second time I get errors. (So first time I do get the API key binded to my object, but the second time just a error)
I'm using the current version of RestKit (0.10)
The code:
- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObject:(id)object
{
Account *account = (Account *)object;
NSLog(#"API_KEY: %#", account.apiKey);
}
- (IBAction) login:(id)sender
{
Account *account = [[Account alloc] init];
account.email = [emailField text];
account.password = [passwordField text];
[[RKObjectManager sharedManager] postObject:account delegate:self];
}
LOG
/// ---> FIRST CLICK
2012-05-25 14:57:00.028 HerokuApp[11154:fb03] API_KEY: 1234567890
/// ---> SECOND CLICK
2012-05-25 14:57:03.427 HerokuApp[11154:fb03] W restkit.network:RKObjectLoader.m:281 Unable to find parser for MIME Type 'text/html'
2012-05-25 14:57:03.427 HerokuApp[11154:fb03] W restkit.network:RKObjectLoader.m:309 Encountered unexpected response with status code: 200 (MIME Type: text/html -> URL: https://api.heroku.com/login -- https://api.heroku.com -- https://api.heroku.com -- https://api.heroku.com)
2012-05-25 14:57:03.429 HerokuApp[11154:fb03] didFailWithError: Error Domain=org.restkit.RestKit.ErrorDomain Code=4 "The operation couldn’t be completed. (org.restkit.RestKit.ErrorDomain error 4.)"
Can anybody help me explaining why this behaviour is occuring?
Perhaps the API behaves differently when you are logged in. From your log messages, it is appearing to return back text/html content, and not something that RestKit knows how to deal with.
Run in the simulator on a machine where Wireshark is capturing packets. Reproduce the error, then find the TCP stream where this is happening and look at it. If you need help, update your question with the result of "Follow Stream" in Wireshark so that we can see the full HTTP traffic.
Related
I have integrated the Google Plus iOS SDK v1.2.1 into my iOS app. After authentication I am trying to fetch the user's activity feed. My code is the following:
GTLServicePlus* plusService = [[GTLServicePlus alloc] init];
[plusService setAuthorizer:[GPPSignIn sharedInstance].authentication];
plusService.retryEnabled = YES;
GTLQueryPlus *query = [GTLQueryPlus queryForActivitiesListWithUserId:#"me" collection:kGTLPlusCollectionPublic];
[plusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLPlusActivityFeed *data,
NSError *error) {
for (GTLPlusActivity *activity in data.items) {
// ITERATE THROUGH THE ACTIVITIES
NSString *publishedDate = activity.published; <---- ERROR
// "PROPERTY 'published' CANNOT BE FOUND
// IN FORWARD CLASS OBJECT "GTLPLusActivity""
// WHY ARE THE VARIABLES SUCH AS published, placeName,
// title, actor etc NOT ACCESSIBLE
}
}];
I am able to successfully retrieve the posts of the user. The GTLPlusActivity class has many properties as shown in the image:
Whenever I try to access the properties using the "." operator such as "activity.actor" in the for loop, it gives the error "Property 'actor' cannot be found in forward class object 'GTLPlusActivity'". Why am I unable to access the properties? I need to display them in a UITableView.
EDIT: Code Snapshot. Error clearly displayed in Red.
Firstly, check the error condition and make sure the error code is nil. I have tried your code, and it works correctly on my end, so most likely, there is a problem with the response you are getting back. Generally activity.actor will return a GTLPlusActivityActor.
Try something like:
if (error) {
NSLog(#"Status: Error: %#", error);
}
else
<Do stuff>
EDIT: Also, our iOS quick-start is a great resource for seeing how we handle certain parts of the code. The ListMoments bit is pretty similar to dealing with Activities.
https://developers.google.com/+/quickstart/ios
EDIT 2: Also, make sure you have all of the right imports. Try
#import "GTLPlusActivity.h"
or
#import "GTLPlus.h"
This is my code:
// Create a service object for executing queries
GTLServiceYouTube *service = [[GTLServiceYouTube alloc] init];
// Services which do not require sign-in may need an API key from the
// API Console
service.APIKey = #"AIzaSyD9pvsUtnegJvwv5z5XrBO5vFTBVpErYN8";
// Create a query
GTLQueryYouTube *query = [GTLQueryYouTube queryForSearchListWithPart:#"id"];
query.maxResults = 50;
query.q = #"hiking boots";
//query.country = #"US";
// Execute the query
GTLServiceTicket *ticket = [service executeQuery:query
completionHandler:^(GTLServiceTicket *ticket, id object, NSError *error) {
// This callback block is run when the fetch completes
if (error == nil) {
GTLYouTubeSearchListResponse *products = object;
// iteration of items and subscript access to items.
for (GTLYouTubeSearchResult *item in products) {
//NSLog(#"%#",item.identifier); - THIS WORKS, BUT GIVES ME THE WHOLE IDENTIFIER, I JUST WANT THE VIDEO ID
NSLog(#"%#",item.identifier.videoId);
}
}else{
NSLog(#"Error: %#", error.description);
}
}];
If you'll notice the comment above my first NSLog, I'm able to print out a number of things without any issue. But if I try to print out a property of item.identifier, the app crashes completely.
The crash log is this:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GTLYouTubeVideo videoId]: unrecognized selector sent
Now, item.identifier is a GTLYouTubeResourceId, so why is it thinking that I'm trying to get properties from a GTLYoutubeVideo???
Thanks for the help!
Try accessing the JSON of the identifier object directly. There appears to be a "videoId" value in there.
like this:
[item.identifier.JSON objectForKey:#"videoId"]
Now, item.identifier is a GTLYouTubeResourceId
Apparently, it isn't.
so why is it thinking that I'm trying to get properties from a GTLYoutubeVideo???
Because you wrote three consecutive question marks. Because it's a GTLYoutubeVideo instance, in fact. Sorry, C (and thus Objective-C) is not a very type-safe language. You can declare objects to be of some type, and they can be assigned a pointer to some other kind of object at runtime.
Here, I suspect you either misread something in the documentation or there's a bug in the client library or this is a weird memory management error, but one thing is sure: the runtime is always right.
I am having a controller where I need issue multiple facebook requests. How do I tell the request appart in this delegate method?
- (void)request:(FBRequest *)request didLoad:(id)result { ... }
I need to do one thing for one request and another thing for the other request.
How about write individual class request & results from delegates , i used to try this when in Single View i need to take Friends List, Checkins Data , User Info.
i ll create three separate delegate results & get results back .
However making multiple requests will work but it will create bad performances when any one of the requests failed or goes wrong.
Hope it helps
Updated :
userInfo *uInfo = [UserInfo alloc]init];
[uinfo getuserDetails];
[uInfo release];
create a protocol to return results of user info back to view class like
In UsuerInfo class
-(void)request:(FBRequest *)request didLoad:(id)result {
[delegate finfinishedGettingUserInfoDetails:result] // convert to array
}
IN your view class get back the results as
-(void)finishedGettingUserInfoDetails : (NSMutableArray *)userArr {
yourInstanceArray = [userArr copy];
}
do this for all multiple requests.
I have a response, which returns SOAP fault in case of exception. I want to handle this SOAP Fault. But, the response I get by deserializing the SOAP response does not have a SOAP Fault.
I have used Sudzc Library to generate the objective C code for my web services.
Help will be appreciated.
Thanks,
Priya
There seems to be a bug in the SoapRequest.m that is bundled with Sudzc.
Specifically, if you take a look at the
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
method and navigate to the following bit of code:
id output = nil;
SoapFault* fault = [SoapFault faultWithXMLDocument: doc];
if([fault hasFault]) {
if(self.action == nil) {
[self handleFault: fault];
} else {
if(self.handler != nil && [self.handler respondsToSelector: self.action]) {
[self.handler performSelector: self.action withObject: output];
} else {
NSLog(#"SOAP Fault: %#", fault);
}
}
}
You can see that output will always be nil when returned to the handler.
To fix this issue, you can simply return the SoapFault instead of the output to your handler like so:
...
[self.handler performSelector: self.action withObject: fault];
...
In your Sudzc return Handler Method, you can [idOfSoapObject isKindOfClass:[SoapFault class]]
If you are already doing this, then I would suggest turning Logging on: your service will have a .logging(BOOL) property. This will log the full soap requests and responses. Here you can check the response manually for a fault.
So I have an iPhone application that needs to:
Post several strings and up to 5 images (stored in memory) to a RoR web application
Parse the JSON returned that will include several strings and an array of URLs (each representing the location of where the uploaded images can be found on the website).
QUESTIONS:
Can this be done with Three20 (would be nice since I'm using it for other things)? And if so, how?
If it can't be done with Three20 ... how would it be accomplished using ASIHttpRequest? Or maybe something baked into the SDK if that is a better option?
Thanks much
Unfortunately there isn't a whole lot of tutorials and good documentation for three20 out there on the web ... so here is how I finally got things working:
- (void) sendToWebsite {
NSString* url = [[NSString stringWithFormat:kRequestURLPath, self.entityId] stringByAppendingString:#".json"] ;
// Prep. the request
TTURLRequest* request = [TTURLRequest requestWithURL: url delegate: self];
request.httpMethod = #"POST";
request.cachePolicy = TTURLRequestCachePolicyNoCache;
// Response will be JSON ... BUT WHY DO I NEED TO DO THIS HERE???
request.response = [[[TTURLJSONResponse alloc] init] autorelease];
// Set a header value
[request setValue:[[UIDevice currentDevice] uniqueIdentifier] forHTTPHeaderField:#"Device-UID"];
// Post a string
[request.parameters setObject:self.entity_title forKey:#"entity_title"];
// Post some images
for (int i = 0; i < [self.photos count]; i++) {
// IS IT POSSIBLE TO ADD A PARAM NAME SO I CAN LOOK FOR THE SAME NAME
// IN THE WEB APPLICATION REGARDLESS OF FILENAME???
[request addFile:UIImagePNGRepresentation([self.winnerImages objectAtIndex:i])
mimeType:#"image/png"
fileName:[NSString stringWithFormat:#"photo_%i.png", i]];
}
// You rails guys will know what this is for
[request.parameters setObject:#"put" forKey:#"_method"];
// Send the request
[request sendSynchronously];
}
Things I still don't understand (or find problematic):
For a posted file, how can I include both a param name AND a filename?
What is the purpose of setting request.response = to whatever? I don't get that.
Answering #2:
You need to supply the handler for the response before you send your request, the TTURLJSONResponse is not the actual response, but it's responsible for handling the response. This is where you'd process the response for your strings and array of URLs.
It's really a protocol called TTURLResponse that defines the following method for implementation:
/**
* Processes the data from a successful request and determines if it is valid.
*
* If the data is not valid, return an error. The data will not be cached if there is an error.
*
* #param request The request this response is bound to.
* #param response The response object, useful for getting the status code.
* #param data The data received from the TTURLRequest.
* #return NSError if there was an error parsing the data. nil otherwise.
*
* #required
*/
- (NSError*)request:(TTURLRequest*)request
processResponse:(NSHTTPURLResponse*)response
data:(id)data;
You chose TTURLJSONResponse as your handler, which is a straight-forward implementation to look at for help on writing your own.