I am using the following code to log in a user to my application using parse.com
[PFUser logInWithUsernameInBackground:usernameString password:passwordString
block:^(PFUser *user, NSError *error) {
if (user) {
// Do stuff after successful login.
NSLog(#"The user has logged in");
} else {
// The login failed. Check error to see why.
}
}];
The code works great and is documented on the Parse.com API Documentation HERE
My problem however is that I want to be able to show an alert to users when their login credentials come back with with an error, currently I get the following error on my console when I try to sign in with invalid credentials: Error: invalid login credentials (Code: 101, Version: 1.2.19)
Thats great, but I have looked everywhere and cant seem to find where that code, is being created... I am looking for it so that I can add different error messages for to my users: i.e.
if ([errorString rangeOfString:#"username"].location == NSNotFound) {
//the issue is not username related
} else
{
NSLog= (#"The username has been taken");
}
Any idea how I can find the string that contains the error and examine it so that I may act accordingly to the error?
the parse error codes are all documented here:
https://parse.com/docs/ios/api/Classes/PFConstants.html
101 is kPFErrorObjectNotFound
and means 'Object doesn't exist, or has an incorrect password.'
during a login it is likely more the later ;)
so:
if(error.code == kPFErrorObjectNotFound) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"parse login error" message:#"Invalid credentials" delegate:nil cancelButtonTitle:#"ok"];
[alert show];
}
dont use the error string of an NSError as you can't really tell if it is suitable for display.
still it is likely in localizedDescription or some other userInfo field
If you look at the documentation for NSError you will see that its userInfo property is a dictionary. From your NSLog you can see that the error key contains the string you are after, so you can access it with
NSString *errorMessage=[error.userInfo objectForKey:#"error"];
Although, rather than parsing strings it is safer to check the error.code value for 101, possibly displaying the error message for more detail. Checking the error code rather than the string will ensure that a change in the string by Parse won't break your code
Related
I have an iOS app that uses Google Drive to sync some files. The app was working fine up until a couple of months ago (it uses iCloud by default for syncing so it wasn't until recently that I learned the Google Drive since was no longer working).
The error I'm getting is:
An error occurred: Error Domain=com.google.HTTPStatus Code=400 "(null)" UserInfo={json={
error = "invalid_grant";
}, data=<7b0a2020 22657272 6f722220 3a202269 6e76616c 69645f67 72616e74 220a7d>}
The OAuth part sets to be OK and I think I'm authorized to access the user's Google Drive. The error happens when I try to list the files at the top level to see if I need to create a special directory for my app.
- (void)createGoogleDocumentsDirIfNeeded:(id<GoogleServiceDelegate>)delegate
{
NSString *parentID = #"root";
GTLQueryDrive *query = [GTLQueryDrive queryForFilesList];
query.q = [NSString stringWithFormat:#"'%#' in parents and title = '%#' and trashed != true", parentID, APP_NAME];
[googleService executeQuery:query completionHandler:^(GTLServiceTicket *ticket,
GTLDriveFileList *files,
NSError *error)
{
if (error == nil)
{
if ( files.items.count == 0)
{
NSLog(#"Creating google documents dir: %#", APP_NAME);
[self createGoogleDocumentsDir:delegate];
}
else
{
GTLDriveFile *file = [files objectAtIndexedSubscript:0];
self.googleDocumentsID = file.identifier;
NSLog(#"Directory exists: %#; fileID = %#", APP_NAME, googleDocumentsID);
[delegate googleDocumentsDirCreated:YES];
}
}
else
{
NSLog(#"An error occurred: %#", error);
}
}];
}
The error is displayed in the last NSLog().
I'm pretty convinced that something has change on Google's side that is causing this. I've reverted to code to a point where I know it worked before and it is still failing.
Possibly I've made some change in our Google Developer's Console that is causing this, but I can't see what.
It is also the case that the Google API Dashboard still shows some successful accesses, so it seems this is not failing for everyone.
Any thoughts as to what could be going on? The "invalid_grant" error seems pretty generic and web searches show it happens in lots of situations. Any help would be appreciated.
As you say, there could be a variety of explanations.
Some to check are:-
has the user withdrawn his permission
are you using an expired refresh token
is the phone's clock accurate
Read https://developers.google.com/identity/protocols/OAuth2UserAgent
The URL used when authenticating a user is https://accounts.google.com/o/oauth2/v2/auth. This endpoint is accessible over SSL, and HTTP connections are refused.
Only for httpS connects for now
I'm trying to put a super basic Soundcloud feature in my app to upload single .wav files using their UI. I followed their guide and I didn't really need anything outside of the bare bones share menu so I assumed this code would work:
NSURL *trackURL = [[NSURL alloc] initWithString:[docsDir stringByAppendingPathComponent:fileToShare]];
SCShareViewController *shareViewController;
shareViewController = [SCShareViewController shareViewControllerWithFileURL:trackURL
completionHandler:^(NSDictionary *trackInfo, NSError *error){
if (SC_CANCELED(error)) {
NSLog(#"Canceled!");
} else if (error) {
NSLog(#"Ooops, something went wrong: %#", [error localizedDescription
]);
} else {
// If you want to do something with the uploaded
// track this is the right place for that.
NSLog(#"Uploaded track: %#", trackInfo);
}
}];
// If your app is a registered foursquare app, you can set the client id and secret.
// The user will then see a place picker where a location can be selected.
// If you don't set them, the user sees a plain plain text filed for the place.
[shareViewController setFoursquareClientID:#"<foursquare client id>"
clientSecret:#"<foursquare client secret>"];
// We can preset the title ...
[shareViewController setTitle:#"Funny sounds"];
// ... and other options like the private flag.
[shareViewController setPrivate:NO];
// Now present the share view controller.
[self presentModalViewController:shareViewController animated:YES];
[trackURL release];
However I get an HTTP 422 error with this appearing in my debug console:
2016-02-29 11:04:47.129 synthQ[801:443840] parameters: {
"track[asset_data]" = "/var/mobile/Containers/Data/Application/EE58E5CA-B30C-44EB-B207-EB3368263319/Documents/bb.wav";
"track[downloadable]" = 1;
"track[post_to][]" = "";
"track[sharing]" = public;
"track[tag_list]" = "\"soundcloud:source=synthQ\"";
"track[title]" = "Funny sounds";
"track[track_type]" = recording;
}
2016-02-29 11:04:47.164 synthQ[801:444011] -[NXOAuth2PostBodyStream open] Stream has been reopened after close
2016-02-29 11:04:47.373 synthQ[801:443840] Upload failed with error: HTTP Error: 422 Error Domain=NXOAuth2HTTPErrorDomain Code=422 "HTTP Error: 422" UserInfo={NSLocalizedDescription=HTTP Error: 422}
Does anyone have any ideas what could be going wrong here?
Thanks!
One of the reason to get HTTP 422 error in SoundCloud is:
If you are trying to upload a file for a first time with a new account, you need to verify your email address to complete your SoundCloud registration in order to upload your files.
There might be other reasons for this error, however for my case it was the case and that solved the problem.
You cannot reference external resources while uploading tracks. You
therefor need to download the track to your computer and then perform
the actual upload to SoundCloud.
Source
Soundcloud file uploading issue HTTP 442
I managed to solve this by using a different constructor that passes the audio file as an NSData object:
shareViewController = [SCShareViewController shareViewControllerWithFileData:[NSData dataWithContentsOfFile:[docsDir stringByAppendingPathComponent:fileToShare]]
completionHandler:^(NSDictionary *trackInfo, NSError *error){
if (SC_CANCELED(error)) {
NSLog(#"Canceled!");
} else if (error) {
NSLog(#"Ooops, something went wrong: %#", [error localizedDescription
]);
} else {
// If you want to do something with the uploaded
// track this is the right place for that.
NSLog(#"Uploaded track: %#", trackInfo);
}
}];
I am using anonymous users in parse and if they are not saved, I issue a network call to save them. The code for saving the user is as follows
PFUser* current = [PFUser currentUser];
if (!current.objectId) {
// The user is newly created, don't run any queries for them until they are saved.
[current saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// We need a saved user to do stuff.
if (!succeeded) {
NSLog(#"Error saving user: %#", error);
} else {
NSLog(#"Saved anonymous user");
// ... load data
}
}];
return;
}
If I run this in the simulator with no internet connection, the save fails (clearly), but succeeded is true and error is nil, so my code goes into loading data even though the user was not saved. In fact the error gets logged in logs but isn't returned in the callback:
Error: Error
Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to
be offline." UserInfo=0x17aa1220
{NSErrorFailingURLStringKey=https://api.parse.com/2/user_signup_or_login,
NSErrorFailingURLKey=https://api.parse.com/2/user_signup_or_login,
NSLocalizedDescription=The Internet connection appears to be offline.,
NSUnderlyingError=0x1792c880 "The Internet connection appears to be
offline."} (Code: 100, Version: 1.2.20)
Is this a bug in the Parse API or am I not using something correctly?
It is not enough to just check the succeeded flag, you should also check the error.
If you are only going to check one of them, check the error.
The following is the pattern I would use:
if (succeeded && !error) {
// success!
} else {
// uh oh :(
}
You can handle the error in the else block by using kPFErrorConnectionFailed which checks for connection.
Example
else {
if(error.code == kPFErrorConnectionFailed)
{
// handle error
}
}
This was a bug which has now been fixed in the latest release of parse.
I am referring "ios 3.5 how to" by Facebook. Here is my code
[FBDialogs presentShareDialogWithParams:params
clientState:nil
handler:
^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
// If there's an error show the relevant message
[self showAlert:[self checkErrorMessage:error]];
} else {
// Check if cancel info is returned and log the event
if (results[#"completionGesture"] &&
[results[#"completionGesture"] isEqualToString:#"cancel"]) {
NSLog(#"User canceled story publishing.");
} else {
// If the post went through show a success message
[self showAlert:[self checkPostId:results]];
}
}
In results I only get didComplete key with value 1. How can I get post_id?
use dictionary
call.dialogData.clientState
How about to see this dictionary call.dialogData.clientState http://developers.facebook.com/docs/reference/ios/3.5/class/FBDialogsData
Have you already checked the results NSDictionary?
Put NSLog(#"Results Dictionary: %#",results); inside your second else statement and check the content of this dictionary.
You'll only get the post_id returned if the user is logged in to Facebook on your app. That is, if the user has authenticated your app. If the user hasn't authenticated your app, this isn't returned.
So try putting say an FBLoginView, logging in, and seeing if the post_id gets returned.
I note that it only getting didComplete on ios5,if you test it on ios6,then can getting both "didComplete" and "completionGesture". It maybe a bug of facebook SDK.
I am using the Google CLient Libraries for Objective C available here..
I have successfully been able to Authorize the user and get refresh token. (Using the GTMOAuthenticaion api embedded within).
In the Selector called after successful authorization I make the Get User Profile request as follows.. (I need the id of currently loggedin/authenticated user)
-(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error != nil) {
NSLog(#"Stop");
} else {
if ([auth canAuthorize]){
[Mediator plusService].authorizer = auth;
// Problematic Line
GTLQueryPlus *profileQuery = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"]; // Notice the UserId Param
profileQuery.completionBlock = ^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
self.mediator.gProfile = object;
} else {
NSLog(#"GPlus Service Error %#", error);
}
};
[[Mediator plusService] executeQuery:profileQuery completionHandler:
^(GTLServiceTicket *ticket, id result, NSError *error) {
if (error)
NSLog(#"Some Service Error %#", error);
}];
}
}
}
If I put "me" as parameter, I get invalid user ID error string in jSON response.
However, If I provide some userId like my own 113632923069489732066 it works perfectly fine and returns the appropriate jSON response..!!
The Example for Google Plus inside Examples folder also fails to get current user profile ending with following error.
Error Domain=com.google.GTLJSONRPCErrorDomain Code=400 "The operation couldn’t be completed. (Invalid user ID: {0})" UserInfo=0x7a670fa0 {NSLocalizedFailureReason=(Invalid user ID: {0}), GTLStructuredError=GTLErrorObject 0x7a67b130: {message:"Invalid user ID: {0}" code:400 data:[2]}, error=Invalid user ID: {0}}
P.S. My API Console application doesn't work with iOS option under installed app but needs be configured with "Other" option. When configured with iOS option, the oAuth fails with invalid_client error response.
My Mistake .. !! And a very silly one .. !!
I was signing in using a Gmail Account that was yet not associated with GPlus .. !! =/