I have a wrapper for encrypting and decrypting using CommonCryptor. Occasionally the decryption process will fail, in which case I fill an error like so:
if (result == kCCSuccess) {
cipherData.length = outLength;
} else {
if (error) {
*error = [NSError errorWithDomain:kBridgeEncryptorErrorDomain
code:result
userInfo:nil];
}
return nil;
}
And then I log the error like this:
if (error != nil) {
DDLogError(#"Decrypt fail %i, %#", [error code], [error localizedDescription]);
}
However, this ends up generating strings like:
2013-01-09 09:15:19.753 [BridgeEncrypter decryptDataFromData:] [Line 83] E: Decrypt fail -4304, The operation couldn’t be completed. (com.***.bridgecrypt error -4304.)
Where the -4304 could be any of the error codes in CommonCryptor.h (-4300 to -4305). Is there a good way to map the error codes to their string values, or do I need to have a switch statement that adjusts the string by hand? If I do have to depend on a switch, would best practice be to put it where the issue is logged or where the error is generated?
I'm not sure what you're looking for here. I'm not familiar with CommonCryptor or how error messages are handled in it.
I can recommend that you lean on NSError and it's userInfo and NSLocalized*Key feature.
For example, if you set a NSLocalizedDescriptionKey in the userInfo dictionary, error:
NSDictionary userInfo = #{
NSLocalizedDescriptionKey : #"This is the error message I want users to see"
};
*error = [NSError errorWithDomain:kBridgeEncryptorErrorDomain
code:result
userInfo:userInfo];
Then This is the error message I want users to see is the string returned by -localizedDescription. Then the calling code can use the string to display a message to the user without needing to reinterpret it.
As to the question of how to link error codes to messages you want users to see, there could be a CommonCryptor function that converts error codes to human readable string. If not, then you could write your own. I would recommend using a switch.
NSString *MyCodeToLocalizedDescription(CCCryptorStatus cryptorStatus)
{
switch(cryptorStatus) {
case kCCDecodeError: return #"This is the error message I want users to see";
…
default: return #"Oh noes, unknown error";
}
}
At that point setting the error is:
NSDictionary userInfo = #{
NSLocalizedDescriptionKey : MyCodeToLocalizedDescription(result)
};
*error = [NSError errorWithDomain:kBridgeEncryptorErrorDomain
code:result
userInfo:userInfo];
Related
I am trying to use Sinch Callout Verification for my iOS App. I have implemented the code according to documentation. And I do receive call on iPhone. Recorded voice tells me to "Please press 1 for verification or hang up if you didn't requested this call"
When I enter "1" from my iPhone keyboard, nothing happens. Computer just keep repeating above message.
But when I hang up I do get a call back in my code with failure.
Below is my code :
NSString* defaultRegion = info.countryAbbr.uppercaseString; //this is my country in upper case and its correct
NSError *parseError = nil;
id<SINPhoneNumber> phoneNumber = [SINPhoneNumberUtil() parse:[info getFullPhoneNo]
defaultRegion:defaultRegion
error:&parseError];
if (!phoneNumber){
// Handle invalid user input
}
NSString *phoneNumberInE164 = [SINPhoneNumberUtil() formatNumber:phoneNumber
format:SINPhoneNumberFormatE164];
id<SINVerification> verification = [SINVerification calloutVerificationWithApplicationKey:#"4ecb3c90-6d92-40c5-9a96-649f84fcc93e"
phoneNumber:phoneNumberInE164];
[verification initiateWithCompletionHandler:^(id<SINInitiationResult> result, NSError *error) {
[SPProgressHud hideAllHUDsForView:self.view animated:YES];
if (result.success) {
// when I enter/press "1" call should hang up and code here should run
} else {
if ([error.domain isEqualToString:SINVerificationErrorDomain] &&
error.code == SINVerificationErrorCancelled) {
// Handle cancellation error code separately
NSLog(#"Verification cancelled: %#", error);
} else {
// Inform user of error, e.g. that input was invalid.
}
}
}];
iOS Version : 11.2.6
Xcode Version : 9.2
Sinch Verification Version : 2.0.6 installed using cocoapods
Language : Objective - C
Country : Pakistan (PK)
Service Provider : Zong (CMPak)
Trying to find out Core Data Errors Error, and looking inside userInfo in NSError returned by MOC's save method.
iphone-core-data-unresolved-error-while-saving
I am not able to make commends or raise questions due to my lack of points.
Can any one point out for me where following keys are defined in Apple Doc, NSValidationErrorObject, NSValidationErrorKey...etc?
My understanding is: if CoreData's Error code == NSValidationMultipleErrorsError, then NSError's userInfo(dictionary) will contain all detailed-single-error information, and all those detailed-single-error will be accessible from an Array stored under "NSDetailedErrorsKey" from userInfo.
I just don't see them (NSValidationErrorObject, NSValidationErrorKe...) in Core Data Constants Reference...??? Are they opaque ?
Thanks.
- (BOOL)saveData {
NSError *error;
if (![_sharedManagedObjectContext save:&error]) {
// If Cocoa generated the error...
NSString *message = nil;
if ([[error domain] isEqualToString:#"NSCocoaErrorDomain"]) {
// ...check whether there's an NSDetailedErrors array
NSDictionary *userInfo = [error userInfo];
if ([userInfo valueForKey:#"NSDetailedErrors"] != nil) {
// ...and loop through the array, if so.
NSArray *errors = [userInfo valueForKey:#"NSDetailedErrors"];
for (NSError *anError in errors) {
NSDictionary *subUserInfo = [anError userInfo];
subUserInfo = [anError userInfo];
// Granted, this indents the NSValidation keys rather a lot
// ...but it's a small loss to keep the code more readable.
NSLog(#"Core Data Save Error\n\n \
NSValidationErrorKey\n%#\n\n \
NSValidationErrorPredicate\n%#\n\n \
NSValidationErrorObject\n%#\n\n \
NSLocalizedDescription\n%#",
[subUserInfo valueForKey:#"NSValidationErrorKey"],
[subUserInfo valueForKey:#"NSValidationErrorPredicate"],
[subUserInfo valueForKey:#"NSValidationErrorObject"],
[subUserInfo valueForKey:#"NSLocalizedDescription"]);
}
}
// If there was no NSDetailedErrors array, print values directly
// from the top-level userInfo object. (Hint: all of these keys
// will have null values when you've got multiple errors sitting
// behind the NSDetailedErrors key.
else {
NSLog(#"Core Data Save Error\n\n \
NSValidationErrorKey\n%#\n\n \
NSValidationErrorPredicate\n%#\n\n \
NSValidationErrorObject\n%#\n\n \
NSLocalizedDescription\n%#",
[userInfo valueForKey:#"NSValidationErrorKey"],
[userInfo valueForKey:#"NSValidationErrorPredicate"],
[userInfo valueForKey:#"NSValidationErrorObject"],
[userInfo valueForKey:#"NSLocalizedDescription"]);
}
}
// Handle mine--or 3rd party-generated--errors
else {
NSLog(#"Custom Error: %#", [error localizedDescription]);
}
return NO;
}
return YES;
}
[1]: https://stackoverflow.com/questions/1283960/iphone-core-data-unresolved-error-while-saving
Following is the quoted from #quellish message, thanks #quellish!
Core Data validation errors are defined in CoreDataErrors.h. I am considering asking Apple to move that stuff out of core data and into Foundation, since Key Value Coding really "owns" validation. Validation errors should always have a errorCode value between NSValidationErrorMinimum and NSValidationErrorMaximum as well.
I have an example validation error that may be helpful to you.
Single validation error (only one property failed): Error Domain=NSCocoaErrorDomain Code=1560 "The operation couldn’t be completed. (Cocoa error 1560.)" UserInfo=0x2808ac0 {NSDetailedErrors=(
"Error Domain=NSCocoaErrorDomain Code=1670 \"Name must be John\" UserInfo=0x2805f30 {NSLocalizedDescription=Name must be John}",
"Error Domain=NSCocoaErrorDomain Code=1570 \"The operation couldn\U2019t be completed. (Cocoa error 1570.)\" UserInfo=0x28089c0 {NSValidationErrorObject=<Employee: 0xc003180> (entity: Employee; id: 0xc0031d0 <x-coredata:///Employee/t6FEF17D8-0306-4959-9BFB-4B806E6ED1302> ; da…
see full text
a multiple looks similar, with additional NSErrors in the array that is the value of the userInfo dictionary for the key NSDetailedErrorsKey.
Note that the top level NSError is a single error with the cocoa error domain and error code 1560. That is NSValidationMultipleErrorsError. That error should always contain additional errors under the NSDetailedErrorsKey.
hope that helps!
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
-(BOOL)sendMessage:(NSMutableDictionary *)_message {
//*** Process _message and convert it to NSData here ***//
NSError *error;
BOOL success = [currentMatch sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error];
if (error != nil) {
NSLog(#"Sending data ERROR");
}
return success;
}
I started a match (stored in currentMatch) with another player and continuously sent data using the above method. Then I turned off the wifi.
However, I am not getting the "Sending data ERROR" log message at all.
Why? I turned off the internet connection, so why is there no error here? What could possibly lead to this scenario?
I've also confirmed that the dictionary I am sending is properly encoded into an NSData object, and success is returning YES.
As per the documentation
Return Value
YES if the data was successfully queued for transmission; NO if the match was unable to queue the data.
The method only enqueues the data for transmission, which happens asynchronously.
If you want to monitor the state of the transmission, implement the proper GKMatchDelegate delegate methods, such as match:didFailWithError:.
However, as stated in the documentation:
The match queues the data and transmits it when the network becomes available.
so if you try to perform the method with no network, the transfer just won't happen until the network is back, meaning that you won't see it failing.
By the way you should check the return value, instead of the error, since the error might be nil despite the operation being unsuccessful.
NSError *error;
BOOL success = [currentMatch sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error];
if (!success) {
NSLog(#"Sending data ERROR\n%#", error);
}
return success;
You need to check the return value of the method to know whether or not an error occurred. You cannot test the error parameter directly.
if (!success) {
NSLog(#"Sending data ERROR -- %#", error);
}
return success;
As to why you don't get an error, that send method is asynchronous. It simply enqueues the data for transmission and immediately returns. You have to catch the error through some other means (I'm not steeped in GameKit to know what that other means might be).
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 .. !! =/